diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 1bdae306ee5e3..00c2e5a1e0d20 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -177,7 +177,7 @@ jobs: # Mapping of base image followed by a comma followed by one or more base tags (comma separated) # Note, org.opencontainers.image.version label will use the first base tag (use the most specific tag first) image-mapping: - - alpine:3.20,alpine3.20,alpine + - alpine:3.21,alpine3.21,alpine - debian:bookworm-slim,bookworm-slim,debian-slim - buildpack-deps:bookworm,bookworm,debian - python:3.13-alpine,python3.13-alpine diff --git a/Cargo.lock b/Cargo.lock index d2f1e8d3f2283..3b8566c057e8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -695,7 +695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -4744,6 +4744,7 @@ dependencies = [ "uv-cache-info", "uv-cache-key", "uv-dirs", + "uv-distribution-filename", "uv-distribution-types", "uv-fs", "uv-normalize", @@ -6051,7 +6052,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/uv-cache/Cargo.toml b/crates/uv-cache/Cargo.toml index 577a84cf5bf10..658681d95efd6 100644 --- a/crates/uv-cache/Cargo.toml +++ b/crates/uv-cache/Cargo.toml @@ -17,9 +17,10 @@ doctest = false workspace = true [dependencies] -uv-dirs = { workspace = true } uv-cache-info = { workspace = true } uv-cache-key = { workspace = true } +uv-dirs = { workspace = true } +uv-distribution-filename = { workspace = true } uv-distribution-types = { workspace = true } uv-fs = { workspace = true, features = ["tokio"] } uv-normalize = { workspace = true } diff --git a/crates/uv-cache/src/archive.rs b/crates/uv-cache/src/archive.rs index 31243f25c7969..c78f337ef745d 100644 --- a/crates/uv-cache/src/archive.rs +++ b/crates/uv-cache/src/archive.rs @@ -1,7 +1,8 @@ use std::path::Path; +use std::str::FromStr; /// A unique identifier for an archive (unzipped wheel) in the cache. -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct ArchiveId(String); impl Default for ArchiveId { @@ -22,3 +23,17 @@ impl AsRef for ArchiveId { self.0.as_ref() } } + +impl std::fmt::Display for ArchiveId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl FromStr for ArchiveId { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_string())) + } +} diff --git a/crates/uv-cache/src/lib.rs b/crates/uv-cache/src/lib.rs index 2e74f59393ad9..b7f15e714c7ff 100644 --- a/crates/uv-cache/src/lib.rs +++ b/crates/uv-cache/src/lib.rs @@ -4,6 +4,7 @@ use std::io; use std::io::Write; use std::ops::Deref; use std::path::{Path, PathBuf}; +use std::str::FromStr; use std::sync::Arc; use rustc_hash::FxHashSet; @@ -11,6 +12,7 @@ use tracing::debug; pub use archive::ArchiveId; use uv_cache_info::Timestamp; +use uv_distribution_filename::WheelFilename; use uv_distribution_types::InstalledDist; use uv_fs::{cachedir, directories, LockedFile}; use uv_normalize::PackageName; @@ -31,6 +33,11 @@ mod cli; mod removal; mod wheel; +/// The version of the archive bucket. +/// +/// Must be kept in-sync with the version in [`CacheBucket::to_str`]. +pub const ARCHIVE_VERSION: u8 = 0; + /// A [`CacheEntry`] which may or may not exist yet. #[derive(Debug, Clone)] pub struct CacheEntry(PathBuf); @@ -278,7 +285,7 @@ impl Cache { // Create a symlink to the directory store. fs_err::create_dir_all(path.as_ref().parent().expect("Cache entry to have parent"))?; - uv_fs::replace_symlink(archive_entry.path(), path.as_ref())?; + self.create_link(&id, path.as_ref())?; Ok(id) } @@ -360,10 +367,30 @@ impl Cache { if bucket.is_dir() { for entry in walkdir::WalkDir::new(bucket) { let entry = entry?; - if entry.file_type().is_symlink() { - if let Ok(target) = fs_err::canonicalize(entry.path()) { - references.insert(target); - } + + // Ignore any `.lock` files. + if entry + .path() + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("lock")) + { + continue; + } + + // Identify entries that match the wheel stem pattern (e.g., `typing-extensions-4.8.0-py3-none-any`). + let Some(filename) = entry + .path() + .file_name() + .and_then(|file_name| file_name.to_str()) + else { + continue; + }; + + if WheelFilename::from_stem(filename).is_err() { + continue; + } + if let Ok(target) = self.resolve_link(entry.path()) { + references.insert(target); } } } @@ -385,10 +412,29 @@ impl Cache { if bucket.is_dir() { for entry in walkdir::WalkDir::new(bucket) { let entry = entry?; - if entry.file_type().is_symlink() { - if let Ok(target) = fs_err::canonicalize(entry.path()) { - references.insert(target); - } + + // Ignore any `.lock` files. + if entry + .path() + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("lock")) + { + continue; + } + + // Identify entries that match the wheel stem pattern (e.g., `typing-extensions-4.8.0-py3-none-any`). + let Some(filename) = entry + .path() + .file_name() + .and_then(|file_name| file_name.to_str()) + else { + continue; + }; + if WheelFilename::from_stem(filename).is_err() { + continue; + } + if let Ok(target) = self.resolve_link(entry.path()) { + references.insert(target); } } } @@ -488,19 +534,29 @@ impl Cache { continue; } - // Remove any symlinks and directories in the revision. The symlinks represent - // unzipped wheels, and the directories represent the source distribution archives. + // Remove everything except the built wheel archive and the metadata. for entry in fs_err::read_dir(entry.path())? { let entry = entry?; let path = entry.path(); - if path.is_dir() { - debug!("Removing unzipped built wheel entry: {}", path.display()); - summary += rm_rf(path)?; - } else if path.is_symlink() { - debug!("Removing unzipped built wheel entry: {}", path.display()); - summary += rm_rf(path)?; + // Retain the resolved metadata (`metadata.msgpack`). + if path + .file_name() + .is_some_and(|file_name| file_name == "metadata.msgpack") + { + continue; + } + + // Retain any built wheel archives. + if path + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("whl")) + { + continue; } + + debug!("Removing unzipped built wheel entry: {}", path.display()); + summary += rm_rf(path)?; } } } @@ -513,10 +569,29 @@ impl Cache { if bucket.is_dir() { for entry in walkdir::WalkDir::new(bucket) { let entry = entry?; - if entry.file_type().is_symlink() { - if let Ok(target) = fs_err::canonicalize(entry.path()) { - references.insert(target); - } + + // Ignore any `.lock` files. + if entry + .path() + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("lock")) + { + continue; + } + + // Identify entries that match the wheel stem pattern (e.g., `typing-extensions-4.8.0-py3-none-any`). + let Some(filename) = entry + .path() + .file_name() + .and_then(|file_name| file_name.to_str()) + else { + continue; + }; + if WheelFilename::from_stem(filename).is_err() { + continue; + } + if let Ok(target) = self.resolve_link(entry.path()) { + references.insert(target); } } } @@ -539,6 +614,164 @@ impl Cache { Ok(summary) } + + /// Create a link to a directory in the archive bucket. + /// + /// On Windows, we write structured data ([`Link`]) to a file containing the archive ID and + /// version. On Unix, we create a symlink to the target directory. + #[cfg(windows)] + pub fn create_link(&self, id: &ArchiveId, dst: impl AsRef) -> io::Result<()> { + // Serialize the link. + let link = Link::new(id.clone()); + let contents = link.to_string(); + + // First, attempt to create a file at the location, but fail if it already exists. + match fs_err::OpenOptions::new() + .write(true) + .create_new(true) + .open(dst.as_ref()) + { + Ok(mut file) => { + // Write the target path to the file. + file.write_all(contents.as_bytes())?; + Ok(()) + } + Err(err) if err.kind() == io::ErrorKind::AlreadyExists => { + // Write to a temporary file, then move it into place. + let temp_dir = tempfile::tempdir_in(dst.as_ref().parent().unwrap())?; + let temp_file = temp_dir.path().join("link"); + fs_err::write(&temp_file, contents.as_bytes())?; + + // Move the symlink into the target location. + fs_err::rename(&temp_file, dst.as_ref())?; + + Ok(()) + } + Err(err) => Err(err), + } + } + + /// Resolve an archive link, returning the fully-resolved path. + /// + /// Returns an error if the link target does not exist. + #[cfg(windows)] + pub fn resolve_link(&self, path: impl AsRef) -> io::Result { + // Deserialize the link. + let contents = fs_err::read_to_string(path.as_ref())?; + let link = Link::from_str(&contents)?; + + // Ignore stale links. + if link.version != ARCHIVE_VERSION { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "The link target does not exist.", + )); + } + + // Reconstruct the path. + let path = self.archive(&link.id); + path.canonicalize() + } + + /// Create a link to a directory in the archive bucket. + /// + /// On Windows, we write structured data ([`Link`]) to a file containing the archive ID and + /// version. On Unix, we create a symlink to the target directory. + #[cfg(unix)] + pub fn create_link(&self, id: &ArchiveId, dst: impl AsRef) -> io::Result<()> { + // Construct the link target. + let src = self.archive(id); + let dst = dst.as_ref(); + + // Attempt to create the symlink directly. + match std::os::unix::fs::symlink(&src, dst) { + Ok(()) => Ok(()), + Err(err) if err.kind() == io::ErrorKind::AlreadyExists => { + // Create a symlink, using a temporary file to ensure atomicity. + let temp_dir = tempfile::tempdir_in(dst.parent().unwrap())?; + let temp_file = temp_dir.path().join("link"); + std::os::unix::fs::symlink(&src, &temp_file)?; + + // Move the symlink into the target location. + fs_err::rename(&temp_file, dst)?; + + Ok(()) + } + Err(err) => Err(err), + } + } + + /// Resolve an archive link, returning the fully-resolved path. + /// + /// Returns an error if the link target does not exist. + #[cfg(unix)] + pub fn resolve_link(&self, path: impl AsRef) -> io::Result { + path.as_ref().canonicalize() + } +} + +/// An archive (unzipped wheel) that exists in the local cache. +#[derive(Debug, Clone)] +#[allow(unused)] +struct Link { + /// The unique ID of the entry in the archive bucket. + id: ArchiveId, + /// The version of the archive bucket. + version: u8, +} + +#[allow(unused)] +impl Link { + /// Create a new [`Archive`] with the given ID and hashes. + fn new(id: ArchiveId) -> Self { + Self { + id, + version: ARCHIVE_VERSION, + } + } +} + +impl Display for Link { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "archive-v{}/{}", self.version, self.id) + } +} + +impl FromStr for Link { + type Err = io::Error; + + fn from_str(s: &str) -> Result { + let mut parts = s.splitn(2, '/'); + let version = parts + .next() + .filter(|s| !s.is_empty()) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing version"))?; + let id = parts + .next() + .filter(|s| !s.is_empty()) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing ID"))?; + + // Parse the archive version from `archive-v{version}/{id}`. + let version = version + .strip_prefix("archive-v") + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing version prefix"))?; + let version = u8::from_str(version).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("failed to parse version: {err}"), + ) + })?; + + // Parse the ID from `archive-v{version}/{id}`. + let id = ArchiveId::from_str(id).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("failed to parse ID: {err}"), + ) + })?; + + Ok(Self { id, version }) + } } pub trait CleanReporter: Send + Sync { @@ -696,7 +929,7 @@ pub enum CacheBucket { /// /// ...may be cached as: /// ```text - /// built-wheels-v3/ + /// built-wheels-v4/ /// ├── git /// │   └── 2122faf3e081fb7a /// │      └── 7a2d650a4a7b4d04 @@ -797,20 +1030,22 @@ impl CacheBucket { fn to_str(self) -> &'static str { match self { // Note that when bumping this, you'll also need to bump it - // in crates/uv/tests/cache_prune.rs. - Self::SourceDistributions => "sdists-v7", + // in `crates/uv/tests/it/cache_prune.rs`. + Self::SourceDistributions => "sdists-v8", Self::FlatIndex => "flat-index-v2", Self::Git => "git-v0", Self::Interpreter => "interpreter-v4", // Note that when bumping this, you'll also need to bump it - // in crates/uv/tests/cache_clean.rs. + // in `crates/uv/tests/it/cache_clean.rs`. Self::Simple => "simple-v15", // Note that when bumping this, you'll also need to bump it - // in crates/uv/tests/cache_prune.rs. - Self::Wheels => "wheels-v3", + // in `crates/uv/tests/it/cache_prune.rs`. + Self::Wheels => "wheels-v4", + // Note that when bumping this, you'll also need to bump + // `ARCHIVE_VERSION` in `crates/uv-cache/src/lib.rs`. Self::Archive => "archive-v0", Self::Builds => "builds-v0", - Self::Environments => "environments-v1", + Self::Environments => "environments-v2", } } @@ -1172,3 +1407,30 @@ impl Refresh { } } } + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::ArchiveId; + + use super::Link; + + #[test] + fn test_link_round_trip() { + let id = ArchiveId::new(); + let link = Link::new(id); + let s = link.to_string(); + let parsed = Link::from_str(&s).unwrap(); + assert_eq!(link.id, parsed.id); + assert_eq!(link.version, parsed.version); + } + + #[test] + fn test_link_deserialize() { + assert!(Link::from_str("archive-v0/foo").is_ok()); + assert!(Link::from_str("archive/foo").is_err()); + assert!(Link::from_str("v1/foo").is_err()); + assert!(Link::from_str("archive-v0/").is_err()); + } +} diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 95f951e376534..d9e08a813e88e 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -1079,15 +1079,23 @@ pub struct PipCompileArgs { /// The Python interpreter to use during resolution. /// - /// A Python interpreter is required for building source distributions to - /// determine package metadata when there are not wheels. + /// A Python interpreter is required for building source distributions to determine package + /// metadata when there are not wheels. + /// + /// The interpreter is also used to determine the default minimum Python version, unless + /// `--python-version` is provided. /// - /// The interpreter is also used to determine the default minimum Python - /// version, unless `--python-version` is provided. + /// This option respects `UV_PYTHON`, but when set via environment variable, it is overridden + /// by `--python-version`. /// - /// See `uv help python` for details on Python discovery and supported - /// request formats. - #[arg(long, verbatim_doc_comment, help_heading = "Python options", value_parser = parse_maybe_string)] + /// See `uv help python` for details on Python discovery and supported request formats. + #[arg( + long, + short, + verbatim_doc_comment, + help_heading = "Python options", + value_parser = parse_maybe_string + )] pub python: Option>, /// Install packages into the system Python environment. @@ -1170,7 +1178,7 @@ pub struct PipCompileArgs { /// /// If a patch version is omitted, the minimum patch version is assumed. For /// example, `3.8` is mapped to `3.8.0`. - #[arg(long, short, help_heading = "Python options")] + #[arg(long, help_heading = "Python options")] pub python_version: Option, /// The platform for which requirements should be resolved. @@ -4498,11 +4506,13 @@ pub struct PythonInstallArgs { /// The Python version(s) to install. /// - /// If not provided, the requested Python version(s) will be read from the `.python-versions` or - /// `.python-version` files. If neither file is present, uv will check if it has installed any - /// Python versions. If not, it will install the latest stable version of Python. + /// If not provided, the requested Python version(s) will be read from the `UV_PYTHON` + /// environment variable then `.python-versions` or `.python-version` files. If none of the + /// above are present, uv will check if it has installed any Python versions. If not, it will + /// install the latest stable version of Python. /// /// See `uv help python` to view supported request formats. + #[arg(env = EnvVars::UV_PYTHON)] pub targets: Vec, /// Set the URL to use as the source for downloading Python installations. diff --git a/crates/uv-distribution-filename/src/wheel.rs b/crates/uv-distribution-filename/src/wheel.rs index e450741ad5556..102778586ce2d 100644 --- a/crates/uv-distribution-filename/src/wheel.rs +++ b/crates/uv-distribution-filename/src/wheel.rs @@ -138,6 +138,13 @@ impl WheelFilename { /// Parse a wheel filename from the stem (e.g., `foo-1.2.3-py3-none-any`). pub fn from_stem(stem: &str) -> Result { + // The wheel stem should not contain the `.whl` extension. + if std::path::Path::new(stem) + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("whl")) + { + return Err(WheelFilenameError::UnexpectedExtension(stem.to_string())); + } Self::parse(stem, stem) } @@ -328,6 +335,8 @@ pub enum WheelFilenameError { MissingAbiTag(String), #[error("The wheel filename \"{0}\" is missing a platform tag")] MissingPlatformTag(String), + #[error("The wheel stem \"{0}\" has an unexpected extension")] + UnexpectedExtension(String), } #[cfg(test)] diff --git a/crates/uv-distribution/src/archive.rs b/crates/uv-distribution/src/archive.rs index cde4b220497fb..9a1dbb86834b3 100644 --- a/crates/uv-distribution/src/archive.rs +++ b/crates/uv-distribution/src/archive.rs @@ -1,4 +1,4 @@ -use uv_cache::{ArchiveId, Cache}; +use uv_cache::{ArchiveId, Cache, ARCHIVE_VERSION}; use uv_distribution_types::Hashed; use uv_pypi_types::HashDigest; @@ -9,17 +9,23 @@ pub struct Archive { pub id: ArchiveId, /// The computed hashes of the archive. pub hashes: Vec, + /// The version of the archive bucket. + pub version: u8, } impl Archive { /// Create a new [`Archive`] with the given ID and hashes. pub(crate) fn new(id: ArchiveId, hashes: Vec) -> Self { - Self { id, hashes } + Self { + id, + hashes, + version: ARCHIVE_VERSION, + } } /// Returns `true` if the archive exists in the cache. pub(crate) fn exists(&self, cache: &Cache) -> bool { - cache.archive(&self.id).exists() + self.version == ARCHIVE_VERSION && cache.archive(&self.id).exists() } } diff --git a/crates/uv-distribution/src/distribution_database.rs b/crates/uv-distribution/src/distribution_database.rs index 14fb52dba5ae6..3c3ef575f49af 100644 --- a/crates/uv-distribution/src/distribution_database.rs +++ b/crates/uv-distribution/src/distribution_database.rs @@ -371,7 +371,7 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> { // If the wheel was unzipped previously, respect it. Source distributions are // cached under a unique revision ID, so unzipped directories are never stale. - match built_wheel.target.canonicalize() { + match self.build_context.cache().resolve_link(&built_wheel.target) { Ok(archive) => { return Ok(LocalWheel { dist: Dist::Source(dist.clone()), diff --git a/crates/uv-distribution/src/error.rs b/crates/uv-distribution/src/error.rs index 0727b88969271..6101f7dd385a8 100644 --- a/crates/uv-distribution/src/error.rs +++ b/crates/uv-distribution/src/error.rs @@ -92,10 +92,6 @@ pub enum Error { Extract(#[from] uv_extract::Error), #[error("The source distribution is missing a `PKG-INFO` file")] MissingPkgInfo, - #[error("The source distribution is missing an `egg-info` directory")] - MissingEggInfo, - #[error("The source distribution is missing a `requires.txt` file")] - MissingRequiresTxt, #[error("The source distribution `{}` has no subdirectory `{}`", _0, _1.display())] MissingSubdirectory(Url, PathBuf), #[error("Failed to extract static metadata from `PKG-INFO`")] diff --git a/crates/uv-distribution/src/index/built_wheel_index.rs b/crates/uv-distribution/src/index/built_wheel_index.rs index 8d51003b2b07e..9e5551d590ff4 100644 --- a/crates/uv-distribution/src/index/built_wheel_index.rs +++ b/crates/uv-distribution/src/index/built_wheel_index.rs @@ -1,6 +1,3 @@ -use crate::index::cached_wheel::CachedWheel; -use crate::source::{HttpRevisionPointer, LocalRevisionPointer, HTTP_REVISION, LOCAL_REVISION}; -use crate::Error; use uv_cache::{Cache, CacheBucket, CacheShard, WheelCache}; use uv_cache_info::CacheInfo; use uv_cache_key::cache_digest; @@ -8,10 +5,13 @@ use uv_configuration::ConfigSettings; use uv_distribution_types::{ DirectUrlSourceDist, DirectorySourceDist, GitSourceDist, Hashed, PathSourceDist, }; -use uv_fs::symlinks; use uv_platform_tags::Tags; use uv_types::HashStrategy; +use crate::index::cached_wheel::CachedWheel; +use crate::source::{HttpRevisionPointer, LocalRevisionPointer, HTTP_REVISION, LOCAL_REVISION}; +use crate::Error; + /// A local index of built distributions for a specific source distribution. #[derive(Debug)] pub struct BuiltWheelIndex<'a> { @@ -203,8 +203,16 @@ impl<'a> BuiltWheelIndex<'a> { let mut candidate: Option = None; // Unzipped wheels are stored as symlinks into the archive directory. - for subdir in symlinks(shard) { - match CachedWheel::from_built_source(&subdir) { + for wheel_dir in uv_fs::entries(shard) { + // Ignore any `.lock` files. + if wheel_dir + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("lock")) + { + continue; + } + + match CachedWheel::from_built_source(&wheel_dir, self.cache) { None => {} Some(dist_info) => { // Pick the wheel with the highest priority diff --git a/crates/uv-distribution/src/index/cached_wheel.rs b/crates/uv-distribution/src/index/cached_wheel.rs index c8186ce6f3211..cacdbf3d9a3e4 100644 --- a/crates/uv-distribution/src/index/cached_wheel.rs +++ b/crates/uv-distribution/src/index/cached_wheel.rs @@ -26,7 +26,7 @@ pub struct CachedWheel { impl CachedWheel { /// Try to parse a distribution from a cached directory name (like `typing-extensions-4.8.0-py3-none-any`). - pub fn from_built_source(path: impl AsRef) -> Option { + pub fn from_built_source(path: impl AsRef, cache: &Cache) -> Option { let path = path.as_ref(); // Determine the wheel filename. @@ -34,7 +34,7 @@ impl CachedWheel { let filename = WheelFilename::from_stem(filename).ok()?; // Convert to a cached wheel. - let archive = path.canonicalize().ok()?; + let archive = cache.resolve_link(path).ok()?; let entry = CacheEntry::from_path(archive); let hashes = Vec::new(); let cache_info = CacheInfo::default(); @@ -127,7 +127,14 @@ impl CachedWheel { // Read the pointer. let pointer = HttpArchivePointer::read_from(path).ok()??; let cache_info = pointer.to_cache_info(); - let Archive { id, hashes } = pointer.into_archive(); + let archive = pointer.into_archive(); + + // Ignore stale pointers. + if !archive.exists(cache) { + return None; + } + + let Archive { id, hashes, .. } = archive; let entry = cache.entry(CacheBucket::Archive, "", id); @@ -151,7 +158,14 @@ impl CachedWheel { // Read the pointer. let pointer = LocalArchivePointer::read_from(path).ok()??; let cache_info = pointer.to_cache_info(); - let Archive { id, hashes } = pointer.into_archive(); + let archive = pointer.into_archive(); + + // Ignore stale pointers. + if !archive.exists(cache) { + return None; + } + + let Archive { id, hashes, .. } = archive; // Convert to a cached wheel. let entry = cache.entry(CacheBucket::Archive, "", id); diff --git a/crates/uv-distribution/src/index/registry_wheel_index.rs b/crates/uv-distribution/src/index/registry_wheel_index.rs index 728adaeccf65e..257ad91b9917d 100644 --- a/crates/uv-distribution/src/index/registry_wheel_index.rs +++ b/crates/uv-distribution/src/index/registry_wheel_index.rs @@ -6,7 +6,7 @@ use uv_cache::{Cache, CacheBucket, WheelCache}; use uv_cache_key::cache_digest; use uv_configuration::ConfigSettings; use uv_distribution_types::{CachedRegistryDist, Hashed, Index, IndexLocations, IndexUrl}; -use uv_fs::{directories, files, symlinks}; +use uv_fs::{directories, files}; use uv_normalize::PackageName; use uv_platform_tags::Tags; use uv_types::HashStrategy; @@ -205,8 +205,16 @@ impl<'a> RegistryWheelIndex<'a> { cache_shard.shard(cache_digest(build_configuration)) }; - for wheel_dir in symlinks(cache_shard) { - if let Some(wheel) = CachedWheel::from_built_source(wheel_dir) { + for wheel_dir in uv_fs::entries(cache_shard) { + // Ignore any `.lock` files. + if wheel_dir + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("lock")) + { + continue; + } + + if let Some(wheel) = CachedWheel::from_built_source(wheel_dir, cache) { if wheel.filename.compatibility(tags).is_compatible() { // Enforce hash-checking based on the source distribution. if revision.satisfies( diff --git a/crates/uv-distribution/src/source/mod.rs b/crates/uv-distribution/src/source/mod.rs index 1d865f798faae..c3935272f8013 100644 --- a/crates/uv-distribution/src/source/mod.rs +++ b/crates/uv-distribution/src/source/mod.rs @@ -10,22 +10,18 @@ use std::borrow::Cow; use std::ops::Bound; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str::FromStr; use std::sync::Arc; -use crate::distribution_database::ManagedClient; -use crate::error::Error; -use crate::metadata::{ArchiveMetadata, GitWorkspaceMember, Metadata}; -use crate::source::built_wheel_metadata::BuiltWheelMetadata; -use crate::source::revision::Revision; -use crate::{Reporter, RequiresDist}; use fs_err::tokio as fs; use futures::{FutureExt, TryStreamExt}; use reqwest::{Response, StatusCode}; use tokio_util::compat::FuturesAsyncReadCompatExt; use tracing::{debug, info_span, instrument, warn, Instrument}; use url::Url; +use zip::ZipArchive; + use uv_cache::{Cache, CacheBucket, CacheEntry, CacheShard, Removal, WheelCache}; use uv_cache_info::CacheInfo; use uv_cache_key::cache_digest; @@ -33,7 +29,7 @@ use uv_client::{ CacheControl, CachedClientError, Connectivity, DataWithCachePolicy, RegistryClient, }; use uv_configuration::{BuildKind, BuildOutput, SourceStrategy}; -use uv_distribution_filename::{EggInfoFilename, SourceDistExtension, WheelFilename}; +use uv_distribution_filename::{SourceDistExtension, WheelFilename}; use uv_distribution_types::{ BuildableSource, DirectorySourceUrl, FileLocation, GitSourceUrl, HashPolicy, Hashed, PathSourceUrl, SourceDist, SourceUrl, @@ -45,12 +41,16 @@ use uv_metadata::read_archive_metadata; use uv_normalize::PackageName; use uv_pep440::{release_specifiers_to_ranges, Version}; use uv_platform_tags::Tags; -use uv_pypi_types::{ - HashAlgorithm, HashDigest, Metadata12, PyProjectToml, RequiresTxt, ResolutionMetadata, -}; +use uv_pypi_types::{HashAlgorithm, HashDigest, PyProjectToml, ResolutionMetadata}; use uv_types::{BuildContext, BuildStack, SourceBuildTrait}; use uv_workspace::pyproject::ToolUvSources; -use zip::ZipArchive; + +use crate::distribution_database::ManagedClient; +use crate::error::Error; +use crate::metadata::{ArchiveMetadata, GitWorkspaceMember, Metadata}; +use crate::source::built_wheel_metadata::BuiltWheelMetadata; +use crate::source::revision::Revision; +use crate::{Reporter, RequiresDist}; mod built_wheel_metadata; mod revision; @@ -2481,8 +2481,8 @@ impl StaticMetadata { } } - // If the source distribution is a source tree, avoid reading `PKG-INFO` or `egg-info`, - // since they could be out-of-date. + // If the source distribution is a source tree, avoid reading `PKG-INFO`, since it could be + // out-of-date. if source.is_source_tree() { return Ok(if dynamic { Self::Dynamic } else { Self::None }); } @@ -2525,51 +2525,7 @@ impl StaticMetadata { Err(err) => return Err(err), } - // Attempt to read static metadata from the `egg-info` directory. - match read_egg_info(source_root, subdirectory, source.name(), source.version()).await { - Ok(metadata) => { - debug!("Found static `egg-info` for: {source}"); - - // Validate the metadata, but ignore it if the metadata doesn't match. - match validate_metadata(source, &metadata) { - Ok(()) => { - // If necessary, mark the metadata as dynamic. - let metadata = if dynamic { - ResolutionMetadata { - dynamic: true, - ..metadata - } - } else { - metadata - }; - return Ok(Self::Some(metadata)); - } - Err(err) => { - debug!("Ignoring `egg-info` for {source}: {err}"); - } - } - } - Err( - err @ (Error::MissingEggInfo - | Error::MissingRequiresTxt - | Error::MissingPkgInfo - | Error::RequiresTxt( - uv_pypi_types::MetadataError::Pep508Error(_) - | uv_pypi_types::MetadataError::RequiresTxtContents(_), - ) - | Error::PkgInfo( - uv_pypi_types::MetadataError::Pep508Error(_) - | uv_pypi_types::MetadataError::DynamicField(_) - | uv_pypi_types::MetadataError::FieldNotFound(_) - | uv_pypi_types::MetadataError::UnsupportedMetadataVersion(_), - )), - ) => { - debug!("No static `egg-info` available for: {source} ({err:?})"); - } - Err(err) => return Err(err), - } - - Ok(if dynamic { Self::Dynamic } else { Self::None }) + Ok(Self::None) } } @@ -2724,139 +2680,6 @@ impl LocalRevisionPointer { } } -/// Read the [`ResolutionMetadata`] by combining a source distribution's `PKG-INFO` file with a -/// `requires.txt`. -/// -/// `requires.txt` is a legacy concept from setuptools. For example, here's -/// `Flask.egg-info/requires.txt` from Flask's 1.0 release: -/// -/// ```txt -/// Werkzeug>=0.14 -/// Jinja2>=2.10 -/// itsdangerous>=0.24 -/// click>=5.1 -/// -/// [dev] -/// pytest>=3 -/// coverage -/// tox -/// sphinx -/// pallets-sphinx-themes -/// sphinxcontrib-log-cabinet -/// -/// [docs] -/// sphinx -/// pallets-sphinx-themes -/// sphinxcontrib-log-cabinet -/// -/// [dotenv] -/// python-dotenv -/// ``` -/// -/// See: -async fn read_egg_info( - source_tree: &Path, - subdirectory: Option<&Path>, - name: Option<&PackageName>, - version: Option<&Version>, -) -> Result { - fn find_egg_info( - source_tree: &Path, - name: Option<&PackageName>, - version: Option<&Version>, - ) -> std::io::Result> { - for entry in fs_err::read_dir(source_tree)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - let path = entry.path(); - if path - .extension() - .is_some_and(|ext| ext.eq_ignore_ascii_case("egg-info")) - { - let Some(file_stem) = path.file_stem() else { - continue; - }; - let Some(file_stem) = file_stem.to_str() else { - continue; - }; - let Ok(file_name) = EggInfoFilename::parse(file_stem) else { - continue; - }; - if let Some(name) = name { - if file_name.name != *name { - debug!("Skipping `{file_stem}.egg-info` due to name mismatch (expected: `{name}`)"); - continue; - } - } - if let Some(version) = version { - if file_name.version.as_ref().is_some_and(|v| v != version) { - debug!("Skipping `{file_stem}.egg-info` due to version mismatch (expected: `{version}`)"); - continue; - } - } - return Ok(Some(path)); - } - } - } - Ok(None) - } - - let directory = match subdirectory { - Some(subdirectory) => Cow::Owned(source_tree.join(subdirectory)), - None => Cow::Borrowed(source_tree), - }; - - // Locate the `egg-info` directory. - let egg_info = match find_egg_info(directory.as_ref(), name, version) { - Ok(Some(path)) => path, - Ok(None) => return Err(Error::MissingEggInfo), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - return Err(Error::MissingEggInfo) - } - Err(err) => return Err(Error::CacheRead(err)), - }; - - // Read the `requires.txt`. - let requires_txt = egg_info.join("requires.txt"); - let content = match fs::read(requires_txt).await { - Ok(content) => content, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - return Err(Error::MissingRequiresTxt); - } - Err(err) => return Err(Error::CacheRead(err)), - }; - - // Parse the `requires.txt. - let requires_txt = RequiresTxt::parse(&content).map_err(Error::RequiresTxt)?; - - // Read the `PKG-INFO` file. - let pkg_info = egg_info.join("PKG-INFO"); - let content = match fs::read(pkg_info).await { - Ok(content) => content, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { - return Err(Error::MissingPkgInfo); - } - Err(err) => return Err(Error::CacheRead(err)), - }; - - // Parse the metadata. - let metadata = Metadata12::parse_metadata(&content).map_err(Error::PkgInfo)?; - - // Determine whether the version is dynamic. - let dynamic = metadata.dynamic.iter().any(|field| field == "version"); - - // Combine the sources. - Ok(ResolutionMetadata { - name: metadata.name, - version: metadata.version, - requires_python: metadata.requires_python, - requires_dist: requires_txt.requires_dist, - provides_extras: requires_txt.provides_extras, - dynamic, - }) -} - /// Read the [`ResolutionMetadata`] from a source distribution's `PKG-INFO` file, if it uses Metadata 2.2 /// or later _and_ none of the required fields (`Requires-Python`, `Requires-Dist`, and /// `Provides-Extra`) are marked as dynamic. diff --git a/crates/uv-fs/src/lib.rs b/crates/uv-fs/src/lib.rs index ce0bdc6865775..5c84928bbf2f3 100644 --- a/crates/uv-fs/src/lib.rs +++ b/crates/uv-fs/src/lib.rs @@ -535,10 +535,10 @@ pub fn directories(path: impl AsRef) -> impl Iterator { .map(|entry| entry.path()) } -/// Iterate over the symlinks in a directory. +/// Iterate over the entries in a directory. /// /// If the directory does not exist, returns an empty iterator. -pub fn symlinks(path: impl AsRef) -> impl Iterator { +pub fn entries(path: impl AsRef) -> impl Iterator { path.as_ref() .read_dir() .ok() @@ -551,11 +551,6 @@ pub fn symlinks(path: impl AsRef) -> impl Iterator { None } }) - .filter(|entry| { - entry - .file_type() - .is_ok_and(|file_type| file_type.is_symlink()) - }) .map(|entry| entry.path()) } diff --git a/crates/uv-install-wheel/src/install.rs b/crates/uv-install-wheel/src/install.rs index b1b8387e62b79..9d1bb8ea17aa5 100644 --- a/crates/uv-install-wheel/src/install.rs +++ b/crates/uv-install-wheel/src/install.rs @@ -2,6 +2,16 @@ //! reading from a zip file. use std::path::Path; +use std::str::FromStr; + +use fs_err as fs; +use fs_err::File; +use tracing::{instrument, trace}; + +use uv_cache_info::CacheInfo; +use uv_distribution_filename::WheelFilename; +use uv_pep440::Version; +use uv_pypi_types::{DirectUrl, Metadata10}; use crate::linker::{LinkMode, Locks}; use crate::wheel::{ @@ -9,12 +19,6 @@ use crate::wheel::{ read_record_file, write_installer_metadata, write_script_entrypoints, LibKind, }; use crate::{Error, Layout}; -use fs_err as fs; -use fs_err::File; -use tracing::{instrument, trace}; -use uv_cache_info::CacheInfo; -use uv_distribution_filename::WheelFilename; -use uv_pypi_types::{DirectUrl, Metadata12}; /// Install the given wheel to the given venv /// @@ -38,9 +42,11 @@ pub fn install_wheel( ) -> Result<(), Error> { let dist_info_prefix = find_dist_info(&wheel)?; let metadata = dist_info_metadata(&dist_info_prefix, &wheel)?; - let Metadata12 { name, version, .. } = Metadata12::parse_metadata(&metadata) + let Metadata10 { name, version } = Metadata10::parse_pkg_info(&metadata) .map_err(|err| Error::InvalidWheel(err.to_string()))?; + let version = Version::from_str(&version)?; + // Validate the wheel name and version. { if name != filename.name { diff --git a/crates/uv-pypi-types/src/metadata/metadata10.rs b/crates/uv-pypi-types/src/metadata/metadata10.rs index 2e41f3ee8399c..98efc300fbb5b 100644 --- a/crates/uv-pypi-types/src/metadata/metadata10.rs +++ b/crates/uv-pypi-types/src/metadata/metadata10.rs @@ -1,8 +1,10 @@ -use crate::metadata::Headers; -use crate::MetadataError; use serde::Deserialize; + use uv_normalize::PackageName; +use crate::metadata::Headers; +use crate::MetadataError; + /// A subset of the full core metadata specification, including only the /// fields that have been consistent across all versions of the specification. /// diff --git a/crates/uv-pypi-types/src/metadata/metadata12.rs b/crates/uv-pypi-types/src/metadata/metadata12.rs deleted file mode 100644 index ef2b2038d3748..0000000000000 --- a/crates/uv-pypi-types/src/metadata/metadata12.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::metadata::{parse_version, Headers}; -use crate::{LenientVersionSpecifiers, MetadataError}; -use serde::Deserialize; -use std::str::FromStr; -use uv_normalize::PackageName; -use uv_pep440::{Version, VersionSpecifiers}; - -/// A subset of the full cure metadata specification, only including the -/// fields that have been consistent across all versions of the specification later than 1.2, with -/// the exception of `Dynamic`, which is optional (but introduced in Metadata 2.2). -/// -/// Python Package Metadata 1.2 is specified in . -#[derive(Deserialize, Debug, Clone)] -#[serde(rename_all = "kebab-case")] -pub struct Metadata12 { - pub name: PackageName, - pub version: Version, - pub requires_python: Option, - pub dynamic: Vec, -} - -impl Metadata12 { - /// Parse the [`Metadata12`] from a `.dist-info/METADATA` file, as included in a built - /// distribution. - pub fn parse_metadata(content: &[u8]) -> Result { - let headers = Headers::parse(content)?; - - // To rely on a source distribution's `PKG-INFO` file, the `Metadata-Version` field must be - // present and set to a value of at least `2.2`. - let metadata_version = headers - .get_first_value("Metadata-Version") - .ok_or(MetadataError::FieldNotFound("Metadata-Version"))?; - - // Parse the version into (major, minor). - let (major, minor) = parse_version(&metadata_version)?; - - // At time of writing: - // > Version of the file format; legal values are “1.0”, “1.1”, “1.2”, “2.1”, “2.2”, and “2.3”. - if (major, minor) < (1, 0) || (major, minor) >= (3, 0) { - return Err(MetadataError::InvalidMetadataVersion(metadata_version)); - } - - let name = PackageName::new( - headers - .get_first_value("Name") - .ok_or(MetadataError::FieldNotFound("Name"))?, - )?; - let version = Version::from_str( - &headers - .get_first_value("Version") - .ok_or(MetadataError::FieldNotFound("Version"))?, - ) - .map_err(MetadataError::Pep440VersionError)?; - let requires_python = headers - .get_first_value("Requires-Python") - .map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python)) - .transpose()? - .map(VersionSpecifiers::from); - let dynamic = headers.get_all_values("Dynamic").collect::>(); - - Ok(Self { - name, - version, - requires_python, - dynamic, - }) - } -} diff --git a/crates/uv-pypi-types/src/metadata/mod.rs b/crates/uv-pypi-types/src/metadata/mod.rs index f6886793c3abf..8f2141d4c4586 100644 --- a/crates/uv-pypi-types/src/metadata/mod.rs +++ b/crates/uv-pypi-types/src/metadata/mod.rs @@ -1,6 +1,5 @@ mod build_requires; mod metadata10; -mod metadata12; mod metadata23; mod metadata_resolver; mod pyproject_toml; @@ -20,7 +19,6 @@ use crate::VerbatimParsedUrl; pub use build_requires::BuildRequires; pub use metadata10::Metadata10; -pub use metadata12::Metadata12; pub use metadata23::Metadata23; pub use metadata_resolver::ResolutionMetadata; pub use pyproject_toml::PyProjectToml; diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index 28b854aa5f860..63b59cf4e4951 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -981,6 +981,7 @@ impl Lock { .metadata .requires_dist .iter() + .flatten() .cloned() .map(|requirement| normalize_requirement(requirement, root)) .collect::>()?; @@ -1777,18 +1778,32 @@ impl Package { let sdist = SourceDist::from_annotated_dist(&id, annotated_dist)?; let wheels = Wheel::from_annotated_dist(annotated_dist)?; let requires_dist = if id.source.is_immutable() { - BTreeSet::default() + None } else { - annotated_dist - .metadata - .as_ref() - .expect("metadata is present") - .requires_dist - .iter() - .cloned() - .map(|requirement| requirement.relative_to(root)) - .collect::>() - .map_err(LockErrorKind::RequirementRelativePath)? + Some( + annotated_dist + .metadata + .as_ref() + .expect("metadata is present") + .requires_dist + .iter() + .cloned() + .map(|requirement| requirement.relative_to(root)) + .collect::>() + .map_err(LockErrorKind::RequirementRelativePath)?, + ) + }; + let provides_extras = if id.source.is_immutable() { + None + } else { + Some( + annotated_dist + .metadata + .as_ref() + .expect("metadata is present") + .provides_extras + .clone(), + ) }; let dependency_groups = if id.source.is_immutable() { BTreeMap::default() @@ -1820,6 +1835,7 @@ impl Package { dependency_groups: BTreeMap::default(), metadata: PackageMetadata { requires_dist, + provides_extras, dependency_groups, }, }) @@ -2402,10 +2418,22 @@ impl Package { { let mut metadata_table = Table::new(); - if !self.metadata.requires_dist.is_empty() { - let requires_dist = self - .metadata - .requires_dist + // Even output the empty list to signal it's *known* empty. + if let Some(provides_extras) = &self.metadata.provides_extras { + let provides_extras = provides_extras + .iter() + .map(|extra| { + serde::Serialize::serialize(&extra, toml_edit::ser::ValueSerializer::new()) + }) + .collect::, _>>()?; + // This is just a list of names, so linebreaking it is excessive. + let provides_extras = Array::from_iter(provides_extras); + metadata_table.insert("provides-extras", value(provides_extras)); + } + + // Even output the empty set to signal it's *known* empty. + if let Some(requires_dist) = &self.metadata.requires_dist { + let requires_dist = requires_dist .iter() .map(|requirement| { serde::Serialize::serialize( @@ -2589,6 +2617,11 @@ impl Package { fn is_dynamic(&self) -> bool { self.id.version.is_none() } + + /// Returns the extras the package provides, if any. + pub fn provides_extras(&self) -> Option<&Vec> { + self.metadata.provides_extras.as_ref() + } } /// Attempts to construct a `VerbatimUrl` from the given normalized `Path`. @@ -2632,8 +2665,12 @@ struct PackageWire { #[derive(Clone, Default, Debug, Eq, PartialEq, serde::Deserialize)] #[serde(rename_all = "kebab-case")] struct PackageMetadata { + // The Options here are so we can distinguish "no info available" + // from "known and empty". + #[serde(default)] + requires_dist: Option>, #[serde(default)] - requires_dist: BTreeSet, + provides_extras: Option>, #[serde(default, rename = "requires-dev", alias = "dependency-groups")] dependency_groups: BTreeMap>, } diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap index b0769642b7388..667f5bf7be0eb 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_missing.snap @@ -86,7 +86,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap index d116e18ee9460..ebe9812796a59 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_optional_present.snap @@ -93,7 +93,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap index 9be0baf32f275..36976ce4900a0 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__hash_required_present.snap @@ -89,7 +89,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap index 58a4ad2271d20..17b5630cf17e7 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_unambiguous.snap @@ -79,7 +79,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, @@ -148,7 +149,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap index 58a4ad2271d20..17b5630cf17e7 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_source_version_unambiguous.snap @@ -79,7 +79,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, @@ -148,7 +149,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_dynamic.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_dynamic.snap index 8a0726607b623..52e8eba943af4 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_dynamic.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_dynamic.snap @@ -54,7 +54,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, @@ -100,7 +101,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, @@ -163,7 +165,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap index 58a4ad2271d20..17b5630cf17e7 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__missing_dependency_version_unambiguous.snap @@ -79,7 +79,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, @@ -148,7 +149,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_has_subdir.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_has_subdir.snap index 61bf7f84037ad..d5189738fc1fe 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_has_subdir.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_has_subdir.snap @@ -63,7 +63,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_no_subdir.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_no_subdir.snap index cdf9d68dc7108..ec5d17db146c6 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_no_subdir.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_direct_no_subdir.snap @@ -61,7 +61,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_directory.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_directory.snap index a9f2849ed9bb6..c7f468be6b8d4 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_directory.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_directory.snap @@ -56,7 +56,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_editable.snap b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_editable.snap index 5357b6934627e..d4f8d2b47f75a 100644 --- a/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_editable.snap +++ b/crates/uv-resolver/src/lock/snapshots/uv_resolver__lock__tests__source_editable.snap @@ -56,7 +56,8 @@ Ok( optional_dependencies: {}, dependency_groups: {}, metadata: PackageMetadata { - requires_dist: {}, + requires_dist: None, + provides_extras: None, dependency_groups: {}, }, }, diff --git a/crates/uv-static/src/env_vars.rs b/crates/uv-static/src/env_vars.rs index 8927509cd2f6c..0c12fbd93a540 100644 --- a/crates/uv-static/src/env_vars.rs +++ b/crates/uv-static/src/env_vars.rs @@ -5,6 +5,17 @@ pub struct EnvVars; #[attribute_env_vars_metadata] impl EnvVars { + /// The path to the binary that was used to invoke uv. + /// + /// This is propagated to all subprocesses spawned by uv. + /// + /// If the executable was invoked through a symbolic link, some platforms will return the path + /// of the symbolic link and other platforms will return the path of the symbolic link’s target. + /// + /// See for security + /// considerations. + pub const UV: &'static str = "UV"; + /// Equivalent to the `--offline` command-line argument. If set, uv will disable network access. pub const UV_OFFLINE: &'static str = "UV_OFFLINE"; diff --git a/crates/uv/src/bin/uv.rs b/crates/uv/src/bin/uv.rs index 261618ca826ee..ee178a739b3b4 100644 --- a/crates/uv/src/bin/uv.rs +++ b/crates/uv/src/bin/uv.rs @@ -7,6 +7,8 @@ use std::process::ExitCode; use uv::main as uv_main; +#[allow(unsafe_code)] fn main() -> ExitCode { - uv_main(std::env::args_os()) + // SAFETY: This is safe because we are running it early in `main` before spawning any threads. + unsafe { uv_main(std::env::args_os()) } } diff --git a/crates/uv/src/commands/pip/compile.rs b/crates/uv/src/commands/pip/compile.rs index 0dc21a51273c5..e16410b8ecc53 100644 --- a/crates/uv/src/commands/pip/compile.rs +++ b/crates/uv/src/commands/pip/compile.rs @@ -1,6 +1,7 @@ use std::collections::BTreeSet; use std::env; use std::path::Path; +use std::str::FromStr; use std::sync::Arc; use anyhow::{anyhow, Result}; @@ -86,14 +87,14 @@ pub(crate) async fn pip_compile( no_build_isolation: bool, no_build_isolation_package: Vec, build_options: BuildOptions, - python_version: Option, + mut python_version: Option, python_platform: Option, universal: bool, exclude_newer: Option, sources: SourceStrategy, annotation_style: AnnotationStyle, link_mode: LinkMode, - python: Option, + mut python: Option, system: bool, python_preference: PythonPreference, concurrency: Concurrency, @@ -103,6 +104,29 @@ pub(crate) async fn pip_compile( printer: Printer, preview: PreviewMode, ) -> Result { + // Respect `UV_PYTHON` + if python.is_none() && python_version.is_none() { + if let Ok(request) = std::env::var("UV_PYTHON") { + if !request.is_empty() { + python = Some(request); + } + } + } + + // If `--python` / `-p` is a simple Python version request, we treat it as `--python-version` + // for backwards compatibility. `-p` was previously aliased to `--python-version` but changed to + // `--python` for consistency with the rest of the CLI in v0.6.0. Since we assume metadata is + // consistent across wheels, it's okay for us to build wheels (to determine metadata) with an + // alternative Python interpreter as long as we solve with the proper Python version tags. + if python_version.is_none() { + if let Some(request) = python.as_ref() { + if let Ok(version) = PythonVersion::from_str(request) { + python_version = Some(version); + python = None; + } + } + } + // If the user requests `extras` but does not provide a valid source (e.g., a `pyproject.toml`), // return an error. if !extras.is_empty() && !requirements.iter().any(RequirementsSource::allows_extras) { @@ -189,8 +213,8 @@ pub(crate) async fn pip_compile( let request = PythonRequest::parse(python); PythonInstallation::find(&request, environment_preference, python_preference, &cache) } else { - // TODO(zanieb): The split here hints at a problem with the abstraction; we should be able to use - // `PythonInstallation::find(...)` here. + // TODO(zanieb): The split here hints at a problem with the request abstraction; we should + // be able to use `PythonInstallation::find(...)` here. let request = if let Some(version) = python_version.as_ref() { // TODO(zanieb): We should consolidate `VersionRequest` and `PythonVersion` PythonRequest::Version(VersionRequest::from(version)) @@ -216,6 +240,7 @@ pub(crate) async fn pip_compile( && python_version.minor() == interpreter.python_minor() }; if no_build.is_none() + && python.is_none() && python_version.version() != interpreter.python_version() && (python_version.patch().is_some() || !matches_without_patch) { diff --git a/crates/uv/src/commands/project/environment.rs b/crates/uv/src/commands/project/environment.rs index 0bff1ca60cdc5..e979379c917ae 100644 --- a/crates/uv/src/commands/project/environment.rs +++ b/crates/uv/src/commands/project/environment.rs @@ -81,7 +81,7 @@ impl CachedEnvironment { let cache_entry = cache.entry(CacheBucket::Environments, interpreter_hash, resolution_hash); if cache.refresh().is_none() { - if let Ok(root) = fs_err::read_link(cache_entry.path()) { + if let Ok(root) = cache.resolve_link(cache_entry.path()) { if let Ok(environment) = PythonEnvironment::from_root(root, cache) { return Ok(Self(environment)); } diff --git a/crates/uv/src/commands/project/init.rs b/crates/uv/src/commands/project/init.rs index abc28411138fc..8bdc083301bce 100644 --- a/crates/uv/src/commands/project/init.rs +++ b/crates/uv/src/commands/project/init.rs @@ -803,12 +803,13 @@ impl InitProjectKind { generate_package_scripts(name, path, build_backend, false)?; } } else { - // Create `hello.py` if it doesn't exist - // TODO(zanieb): Only create `hello.py` if there are no other Python files? - let hello_py = path.join("hello.py"); - if !hello_py.try_exists()? && !bare { + // Create `main.py` if it doesn't exist + // (This isn't intended to be a particularly special or magical filename, just nice) + // TODO(zanieb): Only create `main.py` if there are no other Python files? + let main_py = path.join("main.py"); + if !main_py.try_exists()? && !bare { fs_err::write( - path.join("hello.py"), + path.join("main.py"), indoc::formatdoc! {r#" def main(): print("Hello from {name}!") diff --git a/crates/uv/src/commands/project/install_target.rs b/crates/uv/src/commands/project/install_target.rs index 066afe2cc3737..b9432e1ed5b88 100644 --- a/crates/uv/src/commands/project/install_target.rs +++ b/crates/uv/src/commands/project/install_target.rs @@ -2,7 +2,9 @@ use std::borrow::Cow; use std::path::Path; use std::str::FromStr; -use itertools::Either; +use itertools::{Either, Itertools}; + +use uv_configuration::ExtrasSpecification; use uv_distribution_types::Index; use uv_normalize::PackageName; use uv_pypi_types::{LenientRequirement, VerbatimParsedUrl}; @@ -11,6 +13,8 @@ use uv_scripts::Pep723Script; use uv_workspace::pyproject::{DependencyGroupSpecifier, Source, Sources, ToolUvSources}; use uv_workspace::Workspace; +use crate::commands::project::ProjectError; + /// A target that can be installed from a lockfile. #[derive(Debug, Copy, Clone)] pub(crate) enum InstallTarget<'lock> { @@ -230,4 +234,68 @@ impl<'lock> InstallTarget<'lock> { ), } } + + /// Validate the extras requested by the [`ExtrasSpecification`]. + #[allow(clippy::result_large_err)] + pub(crate) fn validate_extras(self, extras: &ExtrasSpecification) -> Result<(), ProjectError> { + let extras = match extras { + ExtrasSpecification::Some(extras) => { + if extras.is_empty() { + return Ok(()); + } + Either::Left(extras.iter()) + } + ExtrasSpecification::Exclude(extras) => { + if extras.is_empty() { + return Ok(()); + } + Either::Right(extras.iter()) + } + _ => return Ok(()), + }; + + match self { + Self::Project { lock, .. } + | Self::Workspace { lock, .. } + | Self::NonProjectWorkspace { lock, .. } => { + let member_packages: Vec<&Package> = lock + .packages() + .iter() + .filter(|package| self.roots().contains(package.name())) + .collect(); + + // If `provides-extra` is not set in any package, do not perform the check, as this + // means that the lock file was generated on a version of uv that predates when the + // feature was added. + if !member_packages + .iter() + .any(|package| package.provides_extras().is_some()) + { + return Ok(()); + } + + for extra in extras { + if !member_packages.iter().any(|package| { + package + .provides_extras() + .is_some_and(|provides_extras| provides_extras.contains(extra)) + }) { + return match self { + Self::Project { .. } => { + Err(ProjectError::MissingExtraProject(extra.clone())) + } + _ => Err(ProjectError::MissingExtraWorkspace(extra.clone())), + }; + } + } + } + Self::Script { .. } => { + // We shouldn't get here if the list is empty so we can assume it isn't + let extra = extras.into_iter().next().expect("non-empty extras").clone(); + return Err(ProjectError::MissingExtraScript(extra)); + } + } + + Ok(()) + } } diff --git a/crates/uv/src/commands/project/mod.rs b/crates/uv/src/commands/project/mod.rs index df62a2530ebb2..cd78e99a1b375 100644 --- a/crates/uv/src/commands/project/mod.rs +++ b/crates/uv/src/commands/project/mod.rs @@ -23,7 +23,7 @@ use uv_distribution_types::{ use uv_fs::{LockedFile, Simplified, CWD}; use uv_git::ResolvedRepositoryReference; use uv_installer::{SatisfiesResult, SitePackages}; -use uv_normalize::{GroupName, PackageName, DEV_DEPENDENCIES}; +use uv_normalize::{ExtraName, GroupName, PackageName, DEV_DEPENDENCIES}; use uv_pep440::{Version, VersionSpecifiers}; use uv_pep508::MarkerTreeContents; use uv_pypi_types::{ConflictPackage, ConflictSet, Conflicts, Requirement}; @@ -152,6 +152,15 @@ pub(crate) enum ProjectError { #[error("Default group `{0}` (from `tool.uv.default-groups`) is not defined in the project's `dependency-groups` table")] MissingDefaultGroup(GroupName), + #[error("Extra `{0}` is not defined in the project's `optional-dependencies` table")] + MissingExtraProject(ExtraName), + + #[error("Extra `{0}` is not defined in any project's `optional-dependencies` table")] + MissingExtraWorkspace(ExtraName), + + #[error("PEP 723 scripts do not support optional dependencies, but extra `{0}` was specified")] + MissingExtraScript(ExtraName), + #[error("Supported environments must be disjoint, but the following markers overlap: `{0}` and `{1}`.\n\n{hint}{colon} replace `{1}` with `{2}`.", hint = "hint".bold().cyan(), colon = ":".bold())] OverlappingMarkers(String, String, String), diff --git a/crates/uv/src/commands/project/sync.rs b/crates/uv/src/commands/project/sync.rs index 5dc241b0c398d..a87a62edee084 100644 --- a/crates/uv/src/commands/project/sync.rs +++ b/crates/uv/src/commands/project/sync.rs @@ -587,6 +587,7 @@ pub(super) async fn do_sync( } // Validate that the set of requested extras and development groups are compatible. + target.validate_extras(extras)?; detect_conflicts(target.lock(), extras, dev)?; // Determine the markers to use for resolution. diff --git a/crates/uv/src/commands/python/uninstall.rs b/crates/uv/src/commands/python/uninstall.rs index e506a47ace6b6..a1b339a6e8eaa 100644 --- a/crates/uv/src/commands/python/uninstall.rs +++ b/crates/uv/src/commands/python/uninstall.rs @@ -42,7 +42,7 @@ pub(crate) async fn uninstall( if let Some(top_level) = installations.root().parent() { // Remove the `toolchains` symlink. - match uv_fs::remove_symlink(top_level.join("toolchains")) { + match fs_err::tokio::remove_file(top_level.join("toolchains")).await { Ok(()) => {} Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} Err(err) => return Err(err.into()), diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index befe8d81224b9..2cdb7df1455ff 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1269,10 +1269,6 @@ async fn run(mut cli: Cli) -> Result { Commands::Publish(args) => { show_settings!(args); - if globals.preview.is_disabled() { - warn_user_once!("`uv publish` is experimental and may change without warning"); - } - if args.skip_existing { bail!( "`uv publish` does not support `--skip-existing` because there is not a \ @@ -1813,16 +1809,35 @@ async fn run_project( /// The main entry point for a uv invocation. /// -/// WARNING: This entry point is not recommended for external consumption, the -/// uv binary interface is the official public API. When using this entry -/// point, uv assumes it is running in a process it controls and that the -/// entire process lifetime is managed by uv. Unexpected behavior may be -/// encountered if this entry point is called multiple times in a single process. -pub fn main(args: I) -> ExitCode +/// # Usage +/// +/// This entry point is not recommended for external consumption, the uv binary interface is the +/// official public API. +/// +/// When using this entry point, uv assumes it is running in a process it controls and that the +/// entire process lifetime is managed by uv. Unexpected behavior may be encountered if this entry +/// point is called multiple times in a single process. +/// +/// # Safety +/// +/// It is only safe to call this routine when it is known that multiple threads are not running. +#[allow(unsafe_code)] +pub unsafe fn main(args: I) -> ExitCode where I: IntoIterator, T: Into + Clone, { + // Set the `UV` variable to the current executable so it is implicitly propagated to all child + // processes, e.g., in `uv run`. + if let Ok(current_exe) = std::env::current_exe() { + // SAFETY: The proof obligation must be satisfied by the caller. + unsafe { + // This will become unsafe in Rust 2024 + // See https://doc.rust-lang.org/std/env/fn.set_var.html#safety + std::env::set_var(EnvVars::UV, current_exe); + } + } + // `std::env::args` is not `Send` so we parse before passing to our runtime // https://github.com/rust-lang/rust/pull/48005 let cli = match Cli::try_parse_from(args) { diff --git a/crates/uv/tests/it/branching_urls.rs b/crates/uv/tests/it/branching_urls.rs index 759fc67c72792..b87a9d481e7dc 100644 --- a/crates/uv/tests/it/branching_urls.rs +++ b/crates/uv/tests/it/branching_urls.rs @@ -203,7 +203,7 @@ fn root_package_splits_transitive_too() -> Result<()> { "### ); - assert_snapshot!(context.read("uv.lock"), @r###" + assert_snapshot!(context.read("uv.lock"), @r#" version = 1 requires-python = ">=3.11, <3.13" resolution-markers = [ @@ -225,6 +225,7 @@ fn root_package_splits_transitive_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version < '3.12'", specifier = "==4.2.0" }, { name = "anyio", marker = "python_full_version >= '3.12'", specifier = "==4.3.0" }, @@ -273,6 +274,7 @@ fn root_package_splits_transitive_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "b1", marker = "python_full_version < '3.12'", directory = "b1" }, { name = "b2", marker = "python_full_version >= '3.12'", directory = "b2" }, @@ -287,6 +289,7 @@ fn root_package_splits_transitive_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", url = "https://files.pythonhosted.org/packages/9b/dd/b3c12c6d707058fa947864b67f0c4e0c39ef8610988d7baea9578f3c48f3/iniconfig-1.1.1-py2.py3-none-any.whl" }] [[package]] @@ -298,6 +301,7 @@ fn root_package_splits_transitive_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }] [[package]] @@ -320,6 +324,10 @@ fn root_package_splits_transitive_too() -> Result<()> { { url = "https://files.pythonhosted.org/packages/9b/dd/b3c12c6d707058fa947864b67f0c4e0c39ef8610988d7baea9578f3c48f3/iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -331,6 +339,10 @@ fn root_package_splits_transitive_too() -> Result<()> { { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "sniffio" version = "1.3.1" @@ -339,7 +351,7 @@ fn root_package_splits_transitive_too() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "###); + "#); Ok(()) } @@ -398,7 +410,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { "### ); - assert_snapshot!(context.read("uv.lock"), @r###" + assert_snapshot!(context.read("uv.lock"), @r#" version = 1 requires-python = ">=3.11, <3.13" resolution-markers = [ @@ -421,6 +433,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version < '3.12'", specifier = "==4.2.0" }, { name = "anyio", marker = "python_full_version >= '3.12'", specifier = "==4.3.0" }, @@ -469,6 +482,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==1.1.1" }] [[package]] @@ -480,6 +494,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] [[package]] @@ -523,7 +538,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "###); + "#); Ok(()) } @@ -559,7 +574,7 @@ fn branching_between_registry_and_direct_url() -> Result<()> { ); // We have source dist and wheel for the registry, but only the wheel for the direct URL. - assert_snapshot!(context.read("uv.lock"), @r###" + assert_snapshot!(context.read("uv.lock"), @r#" version = 1 requires-python = ">=3.11, <3.13" resolution-markers = [ @@ -580,6 +595,7 @@ fn branching_between_registry_and_direct_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", marker = "python_full_version < '3.12'", specifier = "==1.1.1" }, { name = "iniconfig", marker = "python_full_version >= '3.12'", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }, @@ -607,7 +623,11 @@ fn branching_between_registry_and_direct_url() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] - "###); + + [package.metadata] + provides-extras = [] + requires-dist = [] + "#); Ok(()) } @@ -645,7 +665,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { ); // We have source dist and wheel for the registry, but only the wheel for the direct URL. - assert_snapshot!(context.read("uv.lock"), @r###" + assert_snapshot!(context.read("uv.lock"), @r#" version = 1 requires-python = ">=3.11, <3.13" resolution-markers = [ @@ -666,6 +686,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", marker = "python_full_version < '3.12'", url = "https://files.pythonhosted.org/packages/9b/dd/b3c12c6d707058fa947864b67f0c4e0c39ef8610988d7baea9578f3c48f3/iniconfig-1.1.1-py2.py3-none-any.whl" }, { name = "iniconfig", marker = "python_full_version >= '3.12'", git = "https://github.com/pytest-dev/iniconfig?rev=93f5930e668c0d1ddf4597e38dd0dea4e2665e7a" }, @@ -682,6 +703,10 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { { url = "https://files.pythonhosted.org/packages/9b/dd/b3c12c6d707058fa947864b67f0c4e0c39ef8610988d7baea9578f3c48f3/iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -689,7 +714,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> { resolution-markers = [ "python_full_version >= '3.12'", ] - "###); + "#); Ok(()) } @@ -773,7 +798,7 @@ fn dont_pre_visit_url_packages() -> Result<()> { "### ); - assert_snapshot!(context.read("uv.lock"), @r###" + assert_snapshot!(context.read("uv.lock"), @r#" version = 1 requires-python = ">=3.11, <3.13" @@ -790,6 +815,7 @@ fn dont_pre_visit_url_packages() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "b", directory = "b" }, { name = "c", specifier = "==0.1.0" }, @@ -804,13 +830,18 @@ fn dont_pre_visit_url_packages() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "c", directory = "c" }] [[package]] name = "c" version = "0.1.0" source = { directory = "c" } - "###); + + [package.metadata] + provides-extras = [] + requires-dist = [] + "#); Ok(()) } diff --git a/crates/uv/tests/it/cache_prune.rs b/crates/uv/tests/it/cache_prune.rs index 4cf8642eca523..bb4bd876bbdbb 100644 --- a/crates/uv/tests/it/cache_prune.rs +++ b/crates/uv/tests/it/cache_prune.rs @@ -136,7 +136,7 @@ fn prune_cached_env() { ----- stderr ----- DEBUG uv [VERSION] ([COMMIT] DATE) Pruning cache at: [CACHE_DIR]/ - DEBUG Removing dangling cache environment: [CACHE_DIR]/environments-v1/[ENTRY] + DEBUG Removing dangling cache environment: [CACHE_DIR]/environments-v2/[ENTRY] DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY] Removed [N] files ([SIZE]) "###); @@ -158,7 +158,7 @@ fn prune_stale_symlink() -> Result<()> { .success(); // Remove the wheels directory, causing the symlink to become stale. - let wheels = context.cache_dir.child("wheels-v3"); + let wheels = context.cache_dir.child("wheels-v4"); fs_err::remove_dir_all(wheels)?; let filters: Vec<_> = context @@ -348,7 +348,7 @@ fn prune_stale_revision() -> Result<()> { ----- stderr ----- DEBUG uv [VERSION] ([COMMIT] DATE) Pruning cache at: [CACHE_DIR]/ - DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v7/[ENTRY] + DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v8/[ENTRY] DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY] Removed [N] files ([SIZE]) "###); diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 49bb09962337d..f34e7ca597513 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -362,6 +362,12 @@ impl TestContext { let mut filters = Vec::new(); + filters.extend( + Self::path_patterns(get_bin()) + .into_iter() + .map(|pattern| (pattern, "[UV]".to_string())), + ); + // Exclude `link-mode` on Windows since we set it in the remote test suite if cfg!(windows) { filters.push((" --link-mode ".to_string(), String::new())); diff --git a/crates/uv/tests/it/edit.rs b/crates/uv/tests/it/edit.rs index fa7651252c82d..45e7d63816065 100644 --- a/crates/uv/tests/it/edit.rs +++ b/crates/uv/tests/it/edit.rs @@ -73,7 +73,7 @@ fn add_registry() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -111,6 +111,7 @@ fn add_registry() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -121,7 +122,7 @@ fn add_registry() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -240,7 +241,7 @@ fn add_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -279,6 +280,7 @@ fn add_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", specifier = "==3.7.0" }, { name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1" }, @@ -297,7 +299,7 @@ fn add_git() -> Result<()> { name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -379,7 +381,7 @@ fn add_git_private_source() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -395,13 +397,14 @@ fn add_git_private_source() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-private-pypackage", git = "https://github.com/astral-test/uv-private-pypackage" }] [[package]] name = "uv-private-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-private-pypackage#d780faf0ac91257d4d5a4f0c5a0e4509608c0071" } - "### + "# ); }); @@ -485,7 +488,7 @@ fn add_git_private_raw() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -501,13 +504,14 @@ fn add_git_private_raw() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-private-pypackage", git = "https://github.com/astral-test/uv-private-pypackage" }] [[package]] name = "uv-private-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-private-pypackage#d780faf0ac91257d4d5a4f0c5a0e4509608c0071" } - "### + "# ); }); @@ -705,7 +709,7 @@ fn add_git_raw() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -744,6 +748,7 @@ fn add_git_raw() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", specifier = "==3.7.0" }, { name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=0.0.1" }, @@ -762,7 +767,7 @@ fn add_git_raw() -> Result<()> { name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -969,7 +974,7 @@ fn add_unnamed() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -985,13 +990,14 @@ fn add_unnamed() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -1073,7 +1079,7 @@ fn add_remove_dev() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1113,6 +1119,8 @@ fn add_remove_dev() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [{ name = "anyio", specifier = "==3.7.0" }] @@ -1125,7 +1133,7 @@ fn add_remove_dev() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1196,7 +1204,7 @@ fn add_remove_dev() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1209,10 +1217,12 @@ fn add_remove_dev() -> Result<()> { source = { editable = "." } [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [] - "### + "# ); }); @@ -1294,7 +1304,7 @@ fn add_remove_optional() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1334,6 +1344,7 @@ fn add_remove_optional() -> Result<()> { ] [package.metadata] + provides-extras = ["io"] requires-dist = [{ name = "anyio", marker = "extra == 'io'", specifier = "==3.7.0" }] [[package]] @@ -1344,7 +1355,7 @@ fn add_remove_optional() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1416,7 +1427,7 @@ fn add_remove_optional() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1427,7 +1438,11 @@ fn add_remove_optional() -> Result<()> { name = "project" version = "0.1.0" source = { editable = "." } - "### + + [package.metadata] + provides-extras = ["io"] + requires-dist = [] + "# ); }); @@ -1653,7 +1668,7 @@ fn add_remove_workspace() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1675,13 +1690,18 @@ fn add_remove_workspace() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child2", editable = "child2" }] [[package]] name = "child2" version = "0.1.0" source = { editable = "child2" } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -1736,7 +1756,7 @@ fn add_remove_workspace() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1754,11 +1774,19 @@ fn add_remove_workspace() -> Result<()> { version = "0.1.0" source = { editable = "child1" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "child2" version = "0.1.0" source = { editable = "child2" } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -2283,7 +2311,7 @@ fn add_workspace_editable() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2306,6 +2334,7 @@ fn add_workspace_editable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child2", editable = "child2" }] [[package]] @@ -2313,11 +2342,19 @@ fn add_workspace_editable() -> Result<()> { version = "0.1.0" source = { editable = "child2" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "parent" version = "0.1.0" source = { virtual = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -2407,7 +2444,7 @@ fn add_workspace_path() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2425,6 +2462,10 @@ fn add_workspace_path() -> Result<()> { version = "0.1.0" source = { editable = "child" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "parent" version = "0.1.0" @@ -2434,8 +2475,9 @@ fn add_workspace_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child", editable = "child" }] - "### + "# ); }); @@ -2530,7 +2572,7 @@ fn add_path() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2542,6 +2584,10 @@ fn add_path() -> Result<()> { version = "0.1.0" source = { directory = "packages/child" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "parent" version = "0.1.0" @@ -2551,8 +2597,9 @@ fn add_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child", directory = "packages/child" }] - "### + "# ); }); @@ -2737,7 +2784,7 @@ fn update() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2804,6 +2851,7 @@ fn update() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "requests", extras = ["security"], git = "https://github.com/psf/requests?tag=v2.32.3" }, { name = "requests", extras = ["socks", "use-chardet-on-py3"], marker = "python_full_version >= '3.8'", git = "https://github.com/psf/requests?tag=v2.32.3" }, @@ -2845,7 +2893,7 @@ fn update() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); @@ -3432,7 +3480,7 @@ fn add_inexact() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3457,8 +3505,9 @@ fn add_inexact() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -3571,7 +3620,7 @@ fn remove_registry() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3582,7 +3631,11 @@ fn remove_registry() -> Result<()> { name = "project" version = "0.1.0" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -4254,7 +4307,7 @@ fn add_lower_bound_optional() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -4294,6 +4347,7 @@ fn add_lower_bound_optional() -> Result<()> { ] [package.metadata] + provides-extras = ["io"] requires-dist = [{ name = "anyio", marker = "extra == 'io'", specifier = ">=4.3.0" }] [[package]] @@ -4304,7 +4358,7 @@ fn add_lower_bound_optional() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -4374,7 +4428,7 @@ fn add_lower_bound_local() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -4396,8 +4450,9 @@ fn add_lower_bound_local() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "local-simple-a", specifier = ">=1.2.3" }] - "### + "# ); }); @@ -4475,7 +4530,7 @@ fn add_non_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -4495,7 +4550,7 @@ fn add_non_project() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -5436,7 +5491,7 @@ fn add_remove_script_lock() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -5572,7 +5627,7 @@ fn add_remove_script_lock() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); @@ -6793,7 +6848,7 @@ fn add_warn_index_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6818,8 +6873,9 @@ fn add_warn_index_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "idna", specifier = ">=3.6" }] - "### + "# ); }); @@ -6894,7 +6950,7 @@ fn add_no_warn_index_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6919,8 +6975,9 @@ fn add_no_warn_index_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2.0.0" }] - "### + "# ); }); @@ -6986,7 +7043,7 @@ fn add_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7014,8 +7071,9 @@ fn add_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -7071,7 +7129,7 @@ fn add_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7125,11 +7183,12 @@ fn add_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", specifier = "==2.0.0" }, { name = "jinja2", specifier = ">=3.1.4", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu121" }, ] - "### + "# ); }); @@ -7182,7 +7241,7 @@ fn add_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7241,11 +7300,12 @@ fn add_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", specifier = "==2.0.0" }, { name = "jinja2", specifier = ">=3.1.4", index = "https://test.pypi.org/simple" }, ] - "### + "# ); }); @@ -7301,7 +7361,7 @@ fn add_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7361,6 +7421,7 @@ fn add_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", specifier = "==2.0.0" }, { name = "jinja2", specifier = ">=3.1.4", index = "https://test.pypi.org/simple" }, @@ -7375,7 +7436,7 @@ fn add_index() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); @@ -7429,7 +7490,7 @@ fn add_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7489,6 +7550,7 @@ fn add_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", specifier = "==2.0.0" }, { name = "jinja2", specifier = ">=3.1.4", index = "https://test.pypi.org/simple" }, @@ -7503,7 +7565,7 @@ fn add_index() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); @@ -7564,7 +7626,7 @@ fn add_default_index_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7589,8 +7651,9 @@ fn add_default_index_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2.0.0" }] - "### + "# ); }); @@ -7636,7 +7699,7 @@ fn add_default_index_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7662,6 +7725,7 @@ fn add_default_index_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", specifier = ">=2.0.0" }, { name = "typing-extensions", specifier = ">=4.10.0" }, @@ -7675,7 +7739,7 @@ fn add_default_index_url() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -7736,7 +7800,7 @@ fn add_index_credentials() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7761,8 +7825,9 @@ fn add_index_credentials() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -7831,7 +7896,7 @@ fn existing_index_credentials() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7856,8 +7921,9 @@ fn existing_index_credentials() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -7923,7 +7989,7 @@ fn add_index_with_trailing_slash() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7951,8 +8017,9 @@ fn add_index_with_trailing_slash() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -8018,7 +8085,7 @@ fn add_index_without_trailing_slash() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8046,8 +8113,9 @@ fn add_index_without_trailing_slash() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -8122,7 +8190,7 @@ fn add_group_comment() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -8153,6 +8221,8 @@ fn add_group_comment() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [ @@ -8178,7 +8248,7 @@ fn add_group_comment() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -8255,7 +8325,7 @@ fn add_index_comments() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8280,8 +8350,9 @@ fn add_index_comments() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0" }] - "### + "# ); }); @@ -8556,7 +8627,7 @@ fn add_direct_url_subdirectory() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8594,6 +8665,7 @@ fn add_direct_url_subdirectory() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "root", url = "https://github.com/user-attachments/files/18216295/subdirectory-test.tar.gz", subdirectory = "packages/root" }] [[package]] @@ -8606,6 +8678,7 @@ fn add_direct_url_subdirectory() -> Result<()> { sdist = { hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -8616,7 +8689,7 @@ fn add_direct_url_subdirectory() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -8694,7 +8767,7 @@ fn add_direct_url_subdirectory_raw() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8732,6 +8805,7 @@ fn add_direct_url_subdirectory_raw() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "root", url = "https://github.com/user-attachments/files/18216295/subdirectory-test.tar.gz", subdirectory = "packages/root" }] [[package]] @@ -8744,6 +8818,7 @@ fn add_direct_url_subdirectory_raw() -> Result<()> { sdist = { hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -8754,7 +8829,7 @@ fn add_direct_url_subdirectory_raw() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -9405,7 +9480,7 @@ fn repeated_index_cli_environment_variable() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9430,8 +9505,9 @@ fn repeated_index_cli_environment_variable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2.0.0" }] - "### + "# ); }); @@ -9514,7 +9590,7 @@ fn repeated_index_cli() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9539,8 +9615,9 @@ fn repeated_index_cli() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2.0.0" }] - "### + "# ); }); @@ -9623,7 +9700,7 @@ fn repeated_index_cli_reversed() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9648,8 +9725,9 @@ fn repeated_index_cli_reversed() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2.0.0" }] - "### + "# ); }); diff --git a/crates/uv/tests/it/export.rs b/crates/uv/tests/it/export.rs index 775e1f740083a..b132238d9068e 100644 --- a/crates/uv/tests/it/export.rs +++ b/crates/uv/tests/it/export.rs @@ -520,7 +520,7 @@ fn dependency_conflicting_markers() -> Result<()> { }, { insta::assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -594,6 +594,7 @@ fn dependency_conflicting_markers() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "trio", marker = "sys_platform == 'darwin'", specifier = "==0.25.0" }, { name = "trio", marker = "sys_platform == 'win32'", specifier = "==0.10.0" }, @@ -662,7 +663,7 @@ fn dependency_conflicting_markers() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/17/c9/f86f89f14d52f9f2f652ce24cb2f60141a51d087db1563f3fba94ba07346/trio-0.25.0-py3-none-any.whl", hash = "sha256:e6458efe29cc543e557a91e614e2b51710eba2961669329ce9c862d50c6e8e81", size = 467161 }, ] - "### + "# ); } ); @@ -1217,7 +1218,7 @@ fn non_project_fork() -> Result<()> { }, { insta::assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -1280,6 +1281,7 @@ fn non_project_fork() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "sys_platform == 'linux'", specifier = "==3.0.0" }, { name = "anyio", marker = "sys_platform == 'win32'", specifier = "==2.0.0" }, @@ -1302,7 +1304,7 @@ fn non_project_fork() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); } ); @@ -2113,7 +2115,7 @@ fn script() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" resolution-markers = [ @@ -2180,7 +2182,7 @@ fn script() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); diff --git a/crates/uv/tests/it/help.rs b/crates/uv/tests/it/help.rs index f677508ff4d44..c55b708190491 100644 --- a/crates/uv/tests/it/help.rs +++ b/crates/uv/tests/it/help.rs @@ -480,11 +480,14 @@ fn help_subsubcommand() { [TARGETS]... The Python version(s) to install. - If not provided, the requested Python version(s) will be read from the `.python-versions` - or `.python-version` files. If neither file is present, uv will check if it has installed - any Python versions. If not, it will install the latest stable version of Python. + If not provided, the requested Python version(s) will be read from the `UV_PYTHON` + environment variable then `.python-versions` or `.python-version` files. If none of the + above are present, uv will check if it has installed any Python versions. If not, it will + install the latest stable version of Python. See `uv help python` to view supported request formats. + + [env: UV_PYTHON=] Options: -i, --install-dir @@ -772,7 +775,7 @@ fn help_flag_subsubcommand() { Usage: uv python install [OPTIONS] [TARGETS]... Arguments: - [TARGETS]... The Python version(s) to install + [TARGETS]... The Python version(s) to install [env: UV_PYTHON=] Options: -i, --install-dir The directory to store the Python installation in [env: diff --git a/crates/uv/tests/it/init.rs b/crates/uv/tests/it/init.rs index 9c77fec1d52c6..65c65ef7b1afc 100644 --- a/crates/uv/tests/it/init.rs +++ b/crates/uv/tests/it/init.rs @@ -120,7 +120,7 @@ fn init_application() -> Result<()> { child.create_dir_all()?; let pyproject_toml = child.join("pyproject.toml"); - let hello_py = child.join("hello.py"); + let main_py = child.join("main.py"); uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("--app"), @r###" success: true @@ -148,7 +148,7 @@ fn init_application() -> Result<()> { ); }); - let hello = fs_err::read_to_string(hello_py)?; + let hello = fs_err::read_to_string(main_py)?; insta::with_settings!({ filters => context.filters(), }, { @@ -164,7 +164,7 @@ fn init_application() -> Result<()> { ); }); - uv_snapshot!(context.filters(), context.run().current_dir(&child).arg("hello.py"), @r###" + uv_snapshot!(context.filters(), context.run().current_dir(&child).arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -181,7 +181,7 @@ fn init_application() -> Result<()> { Ok(()) } -/// When `hello.py` already exists, we don't create it again +/// When `main.py` already exists, we don't create it again #[test] fn init_application_hello_exists() -> Result<()> { let context = TestContext::new("3.12"); @@ -190,8 +190,8 @@ fn init_application_hello_exists() -> Result<()> { child.create_dir_all()?; let pyproject_toml = child.join("pyproject.toml"); - let hello_py = child.child("hello.py"); - hello_py.touch()?; + let main_py = child.child("main.py"); + main_py.touch()?; uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("--app"), @r###" success: true @@ -219,7 +219,7 @@ fn init_application_hello_exists() -> Result<()> { ); }); - let hello = fs_err::read_to_string(hello_py)?; + let hello = fs_err::read_to_string(main_py)?; insta::with_settings!({ filters => context.filters(), }, { @@ -231,7 +231,7 @@ fn init_application_hello_exists() -> Result<()> { Ok(()) } -/// When other Python files already exists, we still create `hello.py` +/// When other Python files already exists, we still create `main.py` #[test] fn init_application_other_python_exists() -> Result<()> { let context = TestContext::new("3.12"); @@ -240,7 +240,7 @@ fn init_application_other_python_exists() -> Result<()> { child.create_dir_all()?; let pyproject_toml = child.join("pyproject.toml"); - let hello_py = child.join("hello.py"); + let main_py = child.join("main.py"); let other_py = child.child("foo.py"); other_py.touch()?; @@ -270,7 +270,7 @@ fn init_application_other_python_exists() -> Result<()> { ); }); - let hello = fs_err::read_to_string(hello_py)?; + let hello = fs_err::read_to_string(main_py)?; insta::with_settings!({ filters => context.filters(), }, { @@ -610,15 +610,15 @@ fn init_script() -> Result<()> { let child = context.temp_dir.child("foo"); child.create_dir_all()?; - let script = child.join("hello.py"); + let script = child.join("main.py"); - uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("--script").arg("hello.py"), @r###" + uv_snapshot!(context.filters(), context.init().current_dir(&child).arg("--script").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Initialized script at `hello.py` + Initialized script at `main.py` "###); let script = fs_err::read_to_string(&script)?; @@ -634,7 +634,7 @@ fn init_script() -> Result<()> { def main() -> None: - print("Hello from hello.py!") + print("Hello from main.py!") if __name__ == "__main__": @@ -643,11 +643,11 @@ fn init_script() -> Result<()> { ); }); - uv_snapshot!(context.filters(), context.run().current_dir(&child).arg("python").arg("hello.py"), @r###" + uv_snapshot!(context.filters(), context.run().current_dir(&child).arg("python").arg("main.py"), @r###" success: true exit_code: 0 ----- stdout ----- - Hello from hello.py! + Hello from main.py! ----- stderr ----- "###); @@ -1021,7 +1021,7 @@ fn init_application_current_dir() -> Result<()> { "###); let pyproject = fs_err::read_to_string(dir.join("pyproject.toml"))?; - let hello_py = fs_err::read_to_string(dir.join("hello.py"))?; + let main_py = fs_err::read_to_string(dir.join("main.py"))?; insta::with_settings!({ filters => context.filters(), @@ -1043,7 +1043,7 @@ fn init_application_current_dir() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - hello_py, @r###" + main_py, @r###" def main(): print("Hello from foo!") diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index 7bfa4c11b51ee..8270a9424f34e 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -43,7 +43,7 @@ fn lock_wheel_registry() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -81,6 +81,7 @@ fn lock_wheel_registry() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -91,7 +92,7 @@ fn lock_wheel_registry() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -174,7 +175,7 @@ fn lock_sdist_registry() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -190,6 +191,7 @@ fn lock_sdist_registry() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "source-distribution", specifier = "==0.0.1" }] [[package]] @@ -197,7 +199,7 @@ fn lock_sdist_registry() -> Result<()> { version = "0.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/10/1f/57aa4cce1b1abf6b433106676e15f9fa2c92ed2bd4cf77c3b50a9e9ac773/source_distribution-0.0.1.tar.gz", hash = "sha256:1f83ed7498336c7f2ab9b002cf22583d91115ebc624053dc4eb3a45694490106", size = 2157 } - "### + "# ); }); @@ -271,7 +273,7 @@ fn lock_sdist_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -287,13 +289,14 @@ fn lock_sdist_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -360,7 +363,7 @@ fn lock_sdist_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -376,13 +379,14 @@ fn lock_sdist_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=0dacfd662c64cb4ceb16e6cf65a157a8b715b979" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=0dacfd662c64cb4ceb16e6cf65a157a8b715b979#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -416,7 +420,7 @@ fn lock_sdist_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -432,13 +436,14 @@ fn lock_sdist_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=b270df1a2fb5d012294e9aaf05e7e0bab1e6a389#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -472,7 +477,7 @@ fn lock_sdist_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -488,13 +493,14 @@ fn lock_sdist_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.2" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.2#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -533,7 +539,7 @@ fn lock_sdist_git_subdirectory() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -554,8 +560,9 @@ fn lock_sdist_git_subdirectory() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "example-pkg-a", git = "https://github.com/pypa/sample-namespace-packages.git?subdirectory=pkg_resources%2Fpkg_a&rev=df7530eeb8fa0cb7dbb8ecb28363e8e36bfa2f45" }] - "### + "# ); }); @@ -626,7 +633,7 @@ fn lock_sdist_git_pep508() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -642,13 +649,14 @@ fn lock_sdist_git_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0.0.1" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -689,7 +697,7 @@ fn lock_sdist_git_pep508() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -705,13 +713,14 @@ fn lock_sdist_git_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0dacfd662c64cb4ceb16e6cf65a157a8b715b979" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0dacfd662c64cb4ceb16e6cf65a157a8b715b979#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -742,7 +751,7 @@ fn lock_sdist_git_pep508() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -758,13 +767,14 @@ fn lock_sdist_git_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage.git?rev=b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage.git?rev=b270df1a2fb5d012294e9aaf05e7e0bab1e6a389#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -795,7 +805,7 @@ fn lock_sdist_git_pep508() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -811,13 +821,14 @@ fn lock_sdist_git_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0.0.2" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage.git?rev=0.0.2#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -859,7 +870,7 @@ fn lock_sdist_git_short_rev() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -875,13 +886,14 @@ fn lock_sdist_git_short_rev() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=0dacfd6" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=0dacfd6#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -962,7 +974,7 @@ fn lock_wheel_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -982,6 +994,7 @@ fn lock_wheel_url() -> Result<()> { ] [package.metadata] + provides-extras = ["doc", "test", "trio"] requires-dist = [ { name = "anyio", extras = ["trio"], marker = "extra == 'test'" }, { name = "coverage", extras = ["toml"], marker = "extra == 'test'", specifier = ">=7" }, @@ -1021,6 +1034,7 @@ fn lock_wheel_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl" }] [[package]] @@ -1031,7 +1045,7 @@ fn lock_wheel_url() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1114,7 +1128,7 @@ fn lock_sdist_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1132,6 +1146,7 @@ fn lock_sdist_url() -> Result<()> { sdist = { hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" } [package.metadata] + provides-extras = ["doc", "test", "trio"] requires-dist = [ { name = "anyio", extras = ["trio"], marker = "extra == 'test'" }, { name = "coverage", extras = ["toml"], marker = "extra == 'test'", specifier = ">=7" }, @@ -1171,6 +1186,7 @@ fn lock_sdist_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz" }] [[package]] @@ -1181,7 +1197,7 @@ fn lock_sdist_url() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1256,7 +1272,7 @@ fn lock_sdist_url_subdirectory() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1294,6 +1310,7 @@ fn lock_sdist_url_subdirectory() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "root", url = "https://github.com/user-attachments/files/18216295/subdirectory-test.tar.gz", subdirectory = "packages/root" }] [[package]] @@ -1306,6 +1323,7 @@ fn lock_sdist_url_subdirectory() -> Result<()> { sdist = { hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -1316,7 +1334,7 @@ fn lock_sdist_url_subdirectory() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1389,7 +1407,7 @@ fn lock_sdist_url_subdirectory_pep508() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1427,6 +1445,7 @@ fn lock_sdist_url_subdirectory_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "root", url = "https://github.com/user-attachments/files/18216295/subdirectory-test.tar.gz", subdirectory = "packages/root" }] [[package]] @@ -1439,6 +1458,7 @@ fn lock_sdist_url_subdirectory_pep508() -> Result<()> { sdist = { hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -1449,7 +1469,7 @@ fn lock_sdist_url_subdirectory_pep508() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1525,7 +1545,7 @@ fn lock_project_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1577,6 +1597,7 @@ fn lock_project_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["test"] requires-dist = [ { name = "anyio", specifier = "==3.7.0" }, { name = "iniconfig", marker = "extra == 'test'" }, @@ -1590,7 +1611,7 @@ fn lock_project_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -1894,7 +1915,7 @@ fn lock_dependency_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2000,6 +2021,7 @@ fn lock_dependency_extra() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "flask", extras = ["dotenv"] }] [[package]] @@ -2022,7 +2044,7 @@ fn lock_dependency_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/c3/fc/254c3e9b5feb89ff5b9076a23218dafbc99c96ac5941e900b71206e6313b/werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10", size = 226669 }, ] - "### + "# ); }); @@ -2091,7 +2113,7 @@ fn lock_conditional_dependency_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7" resolution-markers = [ @@ -2228,6 +2250,7 @@ fn lock_conditional_dependency_extra() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "requests" }, { name = "requests", extras = ["socks"], marker = "python_full_version < '3.10'" }, @@ -2287,7 +2310,7 @@ fn lock_conditional_dependency_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); @@ -2388,7 +2411,7 @@ fn lock_dependency_non_existent_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2489,6 +2512,7 @@ fn lock_dependency_non_existent_extra() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "flask", extras = ["foo"] }] [[package]] @@ -2502,7 +2526,7 @@ fn lock_dependency_non_existent_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/c3/fc/254c3e9b5feb89ff5b9076a23218dafbc99c96ac5941e900b71206e6313b/werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10", size = 226669 }, ] - "### + "# ); }); @@ -2568,7 +2592,7 @@ fn lock_upgrade_log() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2600,11 +2624,12 @@ fn lock_upgrade_log() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig" }, { name = "markupsafe", specifier = "<2" }, ] - "### + "# ); }); @@ -2649,7 +2674,7 @@ fn lock_upgrade_log() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2684,6 +2709,7 @@ fn lock_upgrade_log() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "markupsafe" }, { name = "typing-extensions" }, @@ -2697,7 +2723,7 @@ fn lock_upgrade_log() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -2736,7 +2762,7 @@ fn lock_upgrade_log_multi_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -2775,11 +2801,12 @@ fn lock_upgrade_log_multi_version() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "markupsafe", marker = "sys_platform != 'win32'", specifier = "<2" }, { name = "markupsafe", marker = "sys_platform == 'win32'", specifier = "==2.0.0" }, ] - "### + "# ); }); @@ -2821,7 +2848,7 @@ fn lock_upgrade_log_multi_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2855,8 +2882,9 @@ fn lock_upgrade_log_multi_version() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "markupsafe" }] - "### + "# ); }); @@ -2894,7 +2922,7 @@ fn lock_preference() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2919,8 +2947,9 @@ fn lock_preference() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "<2" }] - "### + "# ); }); @@ -2953,7 +2982,7 @@ fn lock_preference() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2978,8 +3007,9 @@ fn lock_preference() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -2999,7 +3029,7 @@ fn lock_preference() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3024,8 +3054,9 @@ fn lock_preference() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -3067,7 +3098,7 @@ fn lock_git_plus_prefix() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3083,13 +3114,14 @@ fn lock_git_plus_prefix() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -3152,7 +3184,7 @@ fn lock_partial_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10" resolution-markers = [ @@ -3221,6 +3253,7 @@ fn lock_partial_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version < '3.12'", git = "https://github.com/agronholm/anyio?rev=4.6.2" }, { name = "anyio", marker = "python_full_version >= '3.12'" }, @@ -3243,7 +3276,7 @@ fn lock_partial_git() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -3441,7 +3474,7 @@ fn lock_git_sha() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3457,13 +3490,14 @@ fn lock_git_sha() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=main" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=main#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -3540,7 +3574,7 @@ fn lock_requires_python() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7" resolution-markers = [ @@ -3670,6 +3704,7 @@ fn lock_requires_python() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "pygls" }] [[package]] @@ -3797,7 +3832,7 @@ fn lock_requires_python() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/5b/fa/c9e82bbe1af6266adf08afb563905eb87cab83fde00a0a08963510621047/zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556", size = 6758 }, ] - "### + "# ); }); @@ -3830,7 +3865,7 @@ fn lock_requires_python() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7.9" resolution-markers = [ @@ -3951,6 +3986,7 @@ fn lock_requires_python() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "pygls" }] [[package]] @@ -4016,7 +4052,7 @@ fn lock_requires_python() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/5b/fa/c9e82bbe1af6266adf08afb563905eb87cab83fde00a0a08963510621047/zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556", size = 6758 }, ] - "### + "# ); }); @@ -4049,7 +4085,7 @@ fn lock_requires_python() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -4099,6 +4135,7 @@ fn lock_requires_python() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "pygls" }] [[package]] @@ -4113,7 +4150,7 @@ fn lock_requires_python() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/4e/1e/643070d8f5c851958662e7e5df16d9c3a068a598a7ee7bb2eb8d95b4e5d7/pygls-1.3.0-py3-none-any.whl", hash = "sha256:d4a01414b6ed4e34e7e8fd29b77d3e88c29615df7d0bbff49bf019e15ec04b8f", size = 56031 }, ] - "### + "# ); }); @@ -4182,7 +4219,7 @@ fn lock_requires_python_upper() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" @@ -4253,8 +4290,9 @@ fn lock_requires_python_upper() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "pydantic" }] - "### + "# ); }); @@ -4306,7 +4344,7 @@ fn lock_requires_python_exact() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.13" @@ -4331,8 +4369,9 @@ fn lock_requires_python_exact() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -4383,7 +4422,7 @@ fn lock_requires_python_fork() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.9" @@ -4424,8 +4463,9 @@ fn lock_requires_python_fork() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv", marker = "python_full_version >= '3.8'" }] - "### + "# ); }); @@ -4477,7 +4517,7 @@ fn lock_requires_python_wheels() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.12.*" @@ -4517,8 +4557,9 @@ fn lock_requires_python_wheels() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "frozenlist" }] - "### + "# ); }); @@ -4560,7 +4601,7 @@ fn lock_requires_python_wheels() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" @@ -4600,8 +4641,9 @@ fn lock_requires_python_wheels() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "frozenlist" }] - "### + "# ); }); @@ -4653,7 +4695,7 @@ fn lock_requires_python_star() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" @@ -4713,6 +4755,7 @@ fn lock_requires_python_star() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "linehaul" }] [[package]] @@ -4723,7 +4766,7 @@ fn lock_requires_python_star() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/9d/ea/6d76df31432a0e6fdf81681a895f009a4bb47b3c39036db3e1b528191d52/pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742", size = 103245 }, ] - "### + "# ); }); @@ -4774,7 +4817,7 @@ fn lock_requires_python_not_equal() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">3.10, !=3.10.9, !=3.10.10, !=3.11.*, <3.13" @@ -4799,8 +4842,9 @@ fn lock_requires_python_not_equal() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -4852,7 +4896,7 @@ fn lock_requires_python_pre() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -4912,6 +4956,7 @@ fn lock_requires_python_pre() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "linehaul" }] [[package]] @@ -4922,7 +4967,7 @@ fn lock_requires_python_pre() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/9d/ea/6d76df31432a0e6fdf81681a895f009a4bb47b3c39036db3e1b528191d52/pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742", size = 103245 }, ] - "### + "# ); }); @@ -4973,7 +5018,7 @@ fn lock_requires_python_unbounded() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "<=3.12" resolution-markers = [ @@ -5018,8 +5063,9 @@ fn lock_requires_python_unbounded() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -5113,7 +5159,7 @@ fn lock_requires_python_maximum_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -5218,8 +5264,9 @@ fn lock_requires_python_maximum_version() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "numpy" }] - "### + "# ); }); @@ -5271,7 +5318,7 @@ fn lock_requires_python_fewest_versions() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -5323,8 +5370,9 @@ fn lock_requires_python_fewest_versions() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "numpy" }] - "### + "# ); }); @@ -5387,7 +5435,7 @@ fn lock_python_version_marker_complement() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -5429,6 +5477,7 @@ fn lock_python_version_marker_complement() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "attrs", marker = "python_full_version < '3.11'" }, { name = "attrs", marker = "python_full_version >= '3.11'" }, @@ -5446,7 +5495,7 @@ fn lock_python_version_marker_complement() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -5497,7 +5546,7 @@ fn lock_dev() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -5527,6 +5576,7 @@ fn lock_dev() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [package.metadata.requires-dev] @@ -5539,7 +5589,11 @@ fn lock_dev() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d" }, ] - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -5610,7 +5664,7 @@ fn lock_conditional_unconditional() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -5635,11 +5689,12 @@ fn lock_conditional_unconditional() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig" }, { name = "iniconfig", marker = "python_full_version < '3.12'" }, ] - "### + "# ); }); @@ -5687,7 +5742,7 @@ fn lock_multiple_markers() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -5712,11 +5767,12 @@ fn lock_multiple_markers() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", marker = "python_full_version < '3.12'" }, { name = "iniconfig", marker = "implementation_name == 'cpython'" }, ] - "### + "# ); }); @@ -5802,7 +5858,7 @@ fn lock_relative_and_absolute_paths() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11, <3.13" @@ -5819,6 +5875,7 @@ fn lock_relative_and_absolute_paths() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "b", directory = "b" }, { name = "c", directory = "c" }, @@ -5829,11 +5886,19 @@ fn lock_relative_and_absolute_paths() -> Result<()> { version = "0.1.0" source = { directory = "b" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "c" version = "0.1.0" source = { directory = "c" } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -5881,7 +5946,7 @@ fn lock_cycles() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -5948,6 +6013,7 @@ fn lock_cycles() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "fixtures", specifier = "==3.0.0" }, { name = "testtools", specifier = "==2.3.0" }, @@ -6014,7 +6080,7 @@ fn lock_cycles() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/72/20/7f0f433060a962200b7272b8c12ba90ef5b903e218174301d0abfd523813/unittest2-1.1.0-py2.py3-none-any.whl", hash = "sha256:13f77d0875db6d9b435e1d4f41e74ad4cc2eb6e1d5c824996092b3430f088bb8", size = 96379 }, ] - "### + "# ); }); @@ -6083,7 +6149,7 @@ fn lock_new_extras() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6141,6 +6207,7 @@ fn lock_new_extras() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "requests", specifier = "==2.31.0" }] [[package]] @@ -6166,7 +6233,7 @@ fn lock_new_extras() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); @@ -6207,7 +6274,7 @@ fn lock_new_extras() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6265,6 +6332,7 @@ fn lock_new_extras() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "requests", extras = ["socks"], specifier = "==2.31.0" }] [[package]] @@ -6304,7 +6372,7 @@ fn lock_new_extras() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); @@ -6453,7 +6521,7 @@ fn lock_resolution_mode() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6491,6 +6559,7 @@ fn lock_resolution_mode() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = ">=3" }] [[package]] @@ -6501,7 +6570,7 @@ fn lock_resolution_mode() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -6533,7 +6602,7 @@ fn lock_resolution_mode() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6572,6 +6641,7 @@ fn lock_resolution_mode() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = ">=3" }] [[package]] @@ -6582,7 +6652,7 @@ fn lock_resolution_mode() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -6694,7 +6764,7 @@ fn lock_same_version_multiple_urls() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -6749,6 +6819,7 @@ fn lock_same_version_multiple_urls() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -6763,6 +6834,7 @@ fn lock_same_version_multiple_urls() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.0.0" }] [[package]] @@ -6784,6 +6856,7 @@ fn lock_same_version_multiple_urls() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dependency", marker = "sys_platform != 'darwin'", directory = "v2" }, { name = "dependency", marker = "sys_platform == 'darwin'", directory = "v1" }, @@ -6797,7 +6870,7 @@ fn lock_same_version_multiple_urls() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -6915,7 +6988,7 @@ fn lock_exclusion() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6931,13 +7004,18 @@ fn lock_exclusion() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "project", virtual = "../" }] [[package]] name = "project" version = "0.1.0" source = { virtual = "../" } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -7219,7 +7297,7 @@ fn lock_peer_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7237,6 +7315,10 @@ fn lock_peer_member() -> Result<()> { version = "0.1.0" source = { editable = "../child" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -7246,8 +7328,9 @@ fn lock_peer_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child", editable = "../child" }] - "### + "# ); }); @@ -7341,7 +7424,7 @@ fn lock_index_workspace_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7363,6 +7446,7 @@ fn lock_index_workspace_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2", index = "https://pypi-proxy.fly.dev/basic-auth/simple" }] [[package]] @@ -7383,8 +7467,9 @@ fn lock_index_workspace_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child", editable = "child" }] - "### + "# ); }); @@ -7489,7 +7574,7 @@ fn lock_dev_transitive() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7513,6 +7598,7 @@ fn lock_dev_transitive() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "baz", editable = "baz" }, { name = "foo", virtual = "../foo" }, @@ -7530,6 +7616,8 @@ fn lock_dev_transitive() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [{ name = "typing-extensions", specifier = ">4" }] @@ -7540,6 +7628,8 @@ fn lock_dev_transitive() -> Result<()> { source = { virtual = "../foo" } [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [{ name = "anyio" }] @@ -7561,7 +7651,7 @@ fn lock_dev_transitive() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -7621,7 +7711,7 @@ fn lock_redact_https() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7637,6 +7727,7 @@ fn lock_redact_https() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -7647,7 +7738,7 @@ fn lock_redact_https() -> Result<()> { wheels = [ { url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -7808,7 +7899,7 @@ fn lock_redact_git_pep508() -> Result<()> { filters => filters.clone(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7824,13 +7915,14 @@ fn lock_redact_git_pep508() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-private-pypackage", git = "https://github.com/astral-test/uv-private-pypackage" }] [[package]] name = "uv-private-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-private-pypackage#d780faf0ac91257d4d5a4f0c5a0e4509608c0071" } - "### + "# ); }); @@ -7900,7 +7992,7 @@ fn lock_redact_git_sources() -> Result<()> { filters => filters.clone(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -7916,13 +8008,14 @@ fn lock_redact_git_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-private-pypackage", git = "https://github.com/astral-test/uv-private-pypackage" }] [[package]] name = "uv-private-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-private-pypackage#d780faf0ac91257d4d5a4f0c5a0e4509608c0071" } - "### + "# ); }); @@ -7990,7 +8083,7 @@ fn lock_redact_git_pep508_non_project() -> Result<()> { filters => filters.clone(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8006,7 +8099,7 @@ fn lock_redact_git_pep508_non_project() -> Result<()> { name = "uv-private-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-private-pypackage#d780faf0ac91257d4d5a4f0c5a0e4509608c0071" } - "### + "# ); }); @@ -8079,7 +8172,7 @@ fn lock_redact_index_sources() -> Result<()> { filters => filters.clone(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8095,6 +8188,7 @@ fn lock_redact_index_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=2", index = "https://pypi-proxy.fly.dev/basic-auth/simple" }] [[package]] @@ -8105,7 +8199,7 @@ fn lock_redact_index_sources() -> Result<()> { wheels = [ { url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -8171,7 +8265,7 @@ fn lock_redact_url_sources() -> Result<()> { filters => filters.clone(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8187,6 +8281,7 @@ fn lock_redact_url_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", url = "https://public:heron@pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }] [[package]] @@ -8196,7 +8291,11 @@ fn lock_redact_url_sources() -> Result<()> { wheels = [ { url = "https://public:heron@pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -8278,7 +8377,7 @@ fn lock_env_credentials() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8294,6 +8393,7 @@ fn lock_env_credentials() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -8304,7 +8404,7 @@ fn lock_env_credentials() -> Result<()> { wheels = [ { url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -8438,7 +8538,7 @@ fn lock_relative_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8454,6 +8554,7 @@ fn lock_relative_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -8464,7 +8565,7 @@ fn lock_relative_index() -> Result<()> { wheels = [ { url = "https://pypi-proxy.fly.dev/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -8549,7 +8650,7 @@ fn lock_no_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8565,6 +8666,7 @@ fn lock_no_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -8590,6 +8692,7 @@ fn lock_no_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", directory = "anyio" }] [package.metadata.requires-dev] @@ -8603,7 +8706,7 @@ fn lock_no_sources() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -8637,7 +8740,7 @@ fn lock_no_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8680,6 +8783,7 @@ fn lock_no_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [package.metadata.requires-dev] @@ -8702,7 +8806,7 @@ fn lock_no_sources() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -8805,7 +8909,7 @@ fn lock_migrate() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8843,6 +8947,7 @@ fn lock_migrate() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -8853,7 +8958,7 @@ fn lock_migrate() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -8903,7 +9008,7 @@ fn lock_upgrade_package() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -8942,6 +9047,7 @@ fn lock_upgrade_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", specifier = "<=2" }, { name = "idna", specifier = "<=3" }, @@ -8955,7 +9061,7 @@ fn lock_upgrade_package() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -8998,7 +9104,7 @@ fn lock_upgrade_package() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9037,6 +9143,7 @@ fn lock_upgrade_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio" }, { name = "idna" }, @@ -9050,7 +9157,7 @@ fn lock_upgrade_package() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -9081,7 +9188,7 @@ fn lock_upgrade_package() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9120,6 +9227,7 @@ fn lock_upgrade_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio" }, { name = "idna" }, @@ -9133,7 +9241,7 @@ fn lock_upgrade_package() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -9270,7 +9378,7 @@ fn lock_find_links_local_wheel() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9286,6 +9394,7 @@ fn lock_find_links_local_wheel() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "tqdm", specifier = "==1000.0.0" }] [[package]] @@ -9295,7 +9404,7 @@ fn lock_find_links_local_wheel() -> Result<()> { wheels = [ { path = "tqdm-1000.0.0-py3-none-any.whl" }, ] - "### + "# ); }); @@ -9383,7 +9492,7 @@ fn lock_find_links_local_sdist() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9399,6 +9508,7 @@ fn lock_find_links_local_sdist() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "tqdm", specifier = "==999.0.0" }] [[package]] @@ -9406,7 +9516,7 @@ fn lock_find_links_local_sdist() -> Result<()> { version = "999.0.0" source = { registry = "../links" } sdist = { path = "tqdm-999.0.0.tar.gz" } - "### + "# ); }); @@ -9473,7 +9583,7 @@ fn lock_find_links_http_wheel() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9498,8 +9608,9 @@ fn lock_find_links_http_wheel() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "packaging", specifier = "==23.2" }] - "### + "# ); }); @@ -9563,7 +9674,7 @@ fn lock_find_links_http_sdist() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9588,8 +9699,9 @@ fn lock_find_links_http_sdist() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "packaging", specifier = "==23.2" }] - "### + "# ); }); @@ -9693,7 +9805,7 @@ fn lock_local_index() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9706,6 +9818,7 @@ fn lock_local_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "tqdm" }] [[package]] @@ -9715,7 +9828,7 @@ fn lock_local_index() -> Result<()> { wheels = [ { path = "tqdm/tqdm-1000.0.0-py3-none-any.whl" }, ] - "### + "# ); }); @@ -9779,7 +9892,7 @@ fn lock_sources_url() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9817,6 +9930,7 @@ fn lock_sources_url() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "workspace", url = "https://github.com/user-attachments/files/16592193/workspace.zip" }] [[package]] @@ -9838,8 +9952,9 @@ fn lock_sources_url() -> Result<()> { sdist = { hash = "sha256:ba690a925dc3d1b53e0675201c9ec26ab59eeec72ab271562f53297bf1817263" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] - "### + "# ); }); @@ -9914,7 +10029,7 @@ fn lock_sources_archive() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -9952,6 +10067,7 @@ fn lock_sources_archive() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "workspace", path = "workspace.zip" }] [[package]] @@ -9973,8 +10089,9 @@ fn lock_sources_archive() -> Result<()> { sdist = { hash = "sha256:ba690a925dc3d1b53e0675201c9ec26ab59eeec72ab271562f53297bf1817263" } [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] - "### + "# ); }); @@ -10064,7 +10181,7 @@ fn lock_sources_source_tree() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10076,6 +10193,10 @@ fn lock_sources_source_tree() -> Result<()> { version = "0.1.0" source = { editable = "workspace/anyio" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -10085,6 +10206,7 @@ fn lock_sources_source_tree() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "workspace", directory = "workspace" }] [[package]] @@ -10096,8 +10218,9 @@ fn lock_sources_source_tree() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", editable = "workspace/anyio" }] - "### + "# ); }); @@ -10200,7 +10323,7 @@ fn lock_editable() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10222,6 +10345,7 @@ fn lock_editable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "library", directory = "library" }] [[package]] @@ -10229,6 +10353,10 @@ fn lock_editable() -> Result<()> { version = "0.1.0" source = { directory = "library" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "workspace" version = "0.1.0" @@ -10238,8 +10366,9 @@ fn lock_editable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "library", directory = "library" }] - "### + "# ); }); @@ -10283,7 +10412,7 @@ fn lock_editable() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10305,6 +10434,7 @@ fn lock_editable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "library", editable = "library" }] [[package]] @@ -10312,6 +10442,10 @@ fn lock_editable() -> Result<()> { version = "0.1.0" source = { editable = "library" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "workspace" version = "0.1.0" @@ -10321,8 +10455,9 @@ fn lock_editable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "library", directory = "library" }] - "### + "# ); }); @@ -10450,7 +10585,7 @@ fn lock_mixed_extras() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10483,6 +10618,7 @@ fn lock_mixed_extras() -> Result<()> { ] [package.metadata] + provides-extras = ["async"] requires-dist = [{ name = "iniconfig", marker = "extra == 'async'", specifier = ">=2" }] [[package]] @@ -10491,6 +10627,7 @@ fn lock_mixed_extras() -> Result<()> { source = { editable = "../workspace2/packages/leaf2" } [package.metadata] + provides-extras = ["async"] requires-dist = [{ name = "packaging", marker = "extra == 'async'", specifier = ">=24" }] [[package]] @@ -10517,6 +10654,7 @@ fn lock_mixed_extras() -> Result<()> { ] [package.metadata] + provides-extras = ["async"] requires-dist = [ { name = "leaf1", editable = "packages/leaf1" }, { name = "typing-extensions", marker = "extra == 'async'", specifier = ">=4" }, @@ -10532,8 +10670,9 @@ fn lock_mixed_extras() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "leaf2", editable = "../workspace2/packages/leaf2" }] - "### + "# ); }); @@ -10643,7 +10782,7 @@ fn lock_transitive_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10676,6 +10815,7 @@ fn lock_transitive_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["async"] requires-dist = [{ name = "iniconfig", marker = "extra == 'async'", specifier = ">=2" }] [[package]] @@ -10702,12 +10842,13 @@ fn lock_transitive_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["async"] requires-dist = [ { name = "leaf", editable = "packages/leaf" }, { name = "leaf", extras = ["async"], marker = "extra == 'async'", editable = "packages/leaf" }, { name = "typing-extensions", marker = "extra == 'async'", specifier = ">=4" }, ] - "### + "# ); }); @@ -10791,7 +10932,7 @@ fn lock_mismatched_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10807,13 +10948,14 @@ fn lock_mismatched_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -10833,7 +10975,7 @@ fn lock_mismatched_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10849,13 +10991,14 @@ fn lock_mismatched_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?rev=0.0.2" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?rev=0.0.2#b270df1a2fb5d012294e9aaf05e7e0bab1e6a389" } - "### + "# ); }); @@ -10900,7 +11043,7 @@ fn lock_mismatched_versions() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -10916,13 +11059,14 @@ fn lock_mismatched_versions() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv-public-pypackage", git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1" }] [[package]] name = "uv-public-pypackage" version = "0.1.0" source = { git = "https://github.com/astral-test/uv-public-pypackage?tag=0.0.1#0dacfd662c64cb4ceb16e6cf65a157a8b715b979" } - "### + "# ); }); @@ -11015,7 +11159,7 @@ fn lock_change_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11040,8 +11184,9 @@ fn lock_change_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -11061,7 +11206,7 @@ fn lock_change_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11086,8 +11231,9 @@ fn lock_change_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -11158,7 +11304,7 @@ fn lock_remove_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11202,6 +11348,7 @@ fn lock_remove_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = ">3" }] [[package]] @@ -11213,6 +11360,7 @@ fn lock_remove_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "leaf", virtual = "leaf" }] [[package]] @@ -11223,7 +11371,7 @@ fn lock_remove_member() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11279,7 +11427,7 @@ fn lock_remove_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11290,7 +11438,11 @@ fn lock_remove_member() -> Result<()> { name = "project" version = "0.1.0" source = { virtual = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -11336,7 +11488,7 @@ fn lock_add_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11347,7 +11499,11 @@ fn lock_add_member() -> Result<()> { name = "project" version = "0.1.0" source = { virtual = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -11446,7 +11602,7 @@ fn lock_add_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11490,6 +11646,7 @@ fn lock_add_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = ">3" }] [[package]] @@ -11497,6 +11654,10 @@ fn lock_add_member() -> Result<()> { version = "0.1.0" source = { virtual = "." } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "sniffio" version = "1.3.1" @@ -11505,7 +11666,7 @@ fn lock_add_member() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11549,7 +11710,7 @@ fn lock_redundant_add_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11587,6 +11748,7 @@ fn lock_redundant_add_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -11597,7 +11759,7 @@ fn lock_redundant_add_member() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11653,7 +11815,7 @@ fn lock_redundant_add_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11692,6 +11854,7 @@ fn lock_redundant_add_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio" }, { name = "idna" }, @@ -11705,7 +11868,7 @@ fn lock_redundant_add_member() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11744,7 +11907,7 @@ fn lock_new_constraints() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11782,6 +11945,7 @@ fn lock_new_constraints() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -11792,7 +11956,7 @@ fn lock_new_constraints() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11850,7 +12014,7 @@ fn lock_new_constraints() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11891,6 +12055,7 @@ fn lock_new_constraints() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [[package]] @@ -11901,7 +12066,7 @@ fn lock_new_constraints() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -11954,7 +12119,7 @@ fn lock_remove_member_non_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -11997,6 +12162,7 @@ fn lock_remove_member_non_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = ">3" }] [[package]] @@ -12007,7 +12173,7 @@ fn lock_remove_member_non_project() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -12108,7 +12274,7 @@ fn lock_rename_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -12133,8 +12299,9 @@ fn lock_rename_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -12188,7 +12355,7 @@ fn lock_rename_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -12213,8 +12380,9 @@ fn lock_rename_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -12303,7 +12471,7 @@ fn lock_missing_metadata() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -12341,6 +12509,7 @@ fn lock_missing_metadata() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -12351,7 +12520,7 @@ fn lock_missing_metadata() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -12453,7 +12622,7 @@ fn lock_dev_dependencies_alias() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -12483,6 +12652,7 @@ fn lock_dev_dependencies_alias() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "typing-extensions" }] [package.metadata.requires-dev] @@ -12496,7 +12666,7 @@ fn lock_dev_dependencies_alias() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -12535,7 +12705,7 @@ fn lock_reorder() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -12583,6 +12753,7 @@ fn lock_reorder() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio" }, { name = "iniconfig" }, @@ -12596,7 +12767,7 @@ fn lock_reorder() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -12684,7 +12855,7 @@ fn lock_narrowed_python_version_upper() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7, <4" resolution-markers = [ @@ -12706,6 +12877,7 @@ fn lock_narrowed_python_version_upper() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -12726,8 +12898,9 @@ fn lock_narrowed_python_version_upper() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "dependency", marker = "python_full_version >= '3.10'", virtual = "dependency" }] - "### + "# ); }); @@ -12794,7 +12967,7 @@ fn lock_narrowed_python_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7" resolution-markers = [ @@ -12815,6 +12988,7 @@ fn lock_narrowed_python_version() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -12835,11 +13009,12 @@ fn lock_narrowed_python_version() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dependency", marker = "python_full_version < '3.9'", directory = "dependency" }, { name = "dependency", marker = "python_full_version >= '3.11'", directory = "dependency" }, ] - "### + "# ); }); @@ -12893,7 +13068,7 @@ fn lock_exclude_unnecessary_python_forks() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -12926,6 +13101,7 @@ fn lock_exclude_unnecessary_python_forks() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version >= '3.11'" }, { name = "anyio", marker = "sys_platform == 'darwin'" }, @@ -12948,7 +13124,7 @@ fn lock_exclude_unnecessary_python_forks() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -13000,7 +13176,7 @@ fn lock_constrained_environment() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -13086,8 +13262,9 @@ fn lock_constrained_environment() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "black" }] - "### + "# ); }); @@ -13177,7 +13354,7 @@ fn lock_constrained_environment() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -13270,8 +13447,9 @@ fn lock_constrained_environment() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "black" }] - "### + "# ); }); @@ -13322,7 +13500,7 @@ fn lock_constrained_environment_legacy() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -13368,6 +13546,7 @@ fn lock_constrained_environment_legacy() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "black" }] [[package]] @@ -13414,7 +13593,7 @@ fn lock_constrained_environment_legacy() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/55/72/4898c44ee9ea6f43396fbc23d9bfaf3d06e01b83698bdf2e4c919deceb7c/platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", size = 17717 }, ] - "### + "# ); }); @@ -13510,7 +13689,7 @@ fn lock_non_project_fork() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10" resolution-markers = [ @@ -13598,7 +13777,7 @@ fn lock_non_project_fork() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -13702,7 +13881,7 @@ fn lock_non_project_conditional() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -13744,7 +13923,7 @@ fn lock_non_project_conditional() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -13810,7 +13989,7 @@ fn lock_non_project_group() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10" @@ -13885,7 +14064,7 @@ fn lock_non_project_group() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -13950,7 +14129,7 @@ fn lock_non_project_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -13969,7 +14148,11 @@ fn lock_non_project_sources() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/d7/77/ff688d1504cdc4db2a938e2b7b9adee5dd52e34efbd2431051efc9984de9/idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a" }, ] - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -14032,7 +14215,7 @@ fn lock_dropped_dev_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14068,10 +14251,12 @@ fn lock_dropped_dev_extra() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] dev = [{ name = "coverage", extras = ["toml"] }] - "### + "# ); }); @@ -14145,7 +14330,7 @@ fn lock_empty_dev_dependencies() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14170,11 +14355,12 @@ fn lock_empty_dev_dependencies() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [package.metadata.requires-dev] dev = [] - "### + "# ); }); @@ -14248,7 +14434,7 @@ fn lock_empty_dependency_group() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14273,11 +14459,12 @@ fn lock_empty_dependency_group() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [package.metadata.requires-dev] empty = [] - "### + "# ); }); @@ -14351,7 +14538,7 @@ fn lock_trailing_slash() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14389,6 +14576,7 @@ fn lock_trailing_slash() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -14399,7 +14587,7 @@ fn lock_trailing_slash() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -14526,7 +14714,7 @@ fn lock_explicit_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14574,6 +14762,7 @@ fn lock_explicit_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", specifier = "==3.7.0" }, { name = "iniconfig", specifier = "==2.0.0", index = "https://test.pypi.org/simple" }, @@ -14587,7 +14776,7 @@ fn lock_explicit_index() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -14633,7 +14822,7 @@ fn lock_explicit_default_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14658,8 +14847,9 @@ fn lock_explicit_default_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0", index = "https://test.pypi.org/simple" }] - "### + "# ); }); @@ -14719,7 +14909,7 @@ fn lock_explicit_default_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14744,8 +14934,9 @@ fn lock_explicit_default_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = "==2.0.0", index = "https://test.pypi.org/simple" }] - "### + "# ); }); @@ -14795,7 +14986,7 @@ fn lock_named_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14811,6 +15002,7 @@ fn lock_named_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "typing-extensions" }] [[package]] @@ -14821,7 +15013,7 @@ fn lock_named_index() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -14863,7 +15055,7 @@ fn lock_default_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14888,8 +15080,9 @@ fn lock_default_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -14925,7 +15118,7 @@ fn lock_default_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -14950,8 +15143,9 @@ fn lock_default_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -15004,7 +15198,7 @@ fn lock_named_index_cli() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15039,8 +15233,9 @@ fn lock_named_index_cli() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "jinja2", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu121" }] - "### + "# ); }); @@ -15091,7 +15286,7 @@ fn lock_repeat_named_index() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15116,8 +15311,9 @@ fn lock_repeat_named_index() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -15164,7 +15360,7 @@ fn lock_repeat_named_index_cli() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15208,8 +15404,9 @@ fn lock_repeat_named_index_cli() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "jinja2", specifier = "==3.1.2" }] - "### + "# ); }); @@ -15230,7 +15427,7 @@ fn lock_repeat_named_index_cli() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15279,8 +15476,9 @@ fn lock_repeat_named_index_cli() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "jinja2", specifier = "==3.1.2" }] - "### + "# ); }); @@ -15328,7 +15526,7 @@ fn lock_explicit_virtual_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15448,6 +15646,7 @@ fn lock_explicit_virtual_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "black" }] [package.metadata.requires-dev] @@ -15461,7 +15660,7 @@ fn lock_explicit_virtual_project() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -15545,7 +15744,7 @@ fn lock_implicit_virtual_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15665,6 +15864,7 @@ fn lock_implicit_virtual_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "black" }] [package.metadata.requires-dev] @@ -15678,7 +15878,7 @@ fn lock_implicit_virtual_project() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -15772,7 +15972,7 @@ fn lock_implicit_virtual_path() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -15801,6 +16001,7 @@ fn lock_implicit_virtual_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">1" }] [[package]] @@ -15831,6 +16032,7 @@ fn lock_implicit_virtual_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", specifier = ">3" }, { name = "child", virtual = "child" }, @@ -15844,7 +16046,7 @@ fn lock_implicit_virtual_path() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -15954,7 +16156,7 @@ fn lock_split_python_environment() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.7" resolution-markers = [ @@ -15978,6 +16180,7 @@ fn lock_split_python_environment() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "uv", marker = "python_full_version >= '3.8'" }] [[package]] @@ -16003,7 +16206,7 @@ fn lock_split_python_environment() -> Result<()> { { url = "https://files.pythonhosted.org/packages/c0/8b/a83689be89c764c98dd19be9e1a044e64ad9c1d17643c5c08262f640908f/uv-0.1.24-py3-none-win32.whl", hash = "sha256:a273f468f170b12e6cb6362aa90a65dd12a397db02df55ffb47a21c11b577d8c", size = 8143891 }, { url = "https://files.pythonhosted.org/packages/d6/7d/55d81e3ecab3595ba9f7be7b394fec61d1e33c1852452e7997bc8022b6f0/uv-0.1.24-py3-none-win_amd64.whl", hash = "sha256:87cce6b44a86e761f845a85e52ea0de44fcd579b9a63b2d856118b0d1847bca7", size = 9178836 }, ] - "### + "# ); }); @@ -16064,7 +16267,7 @@ fn lock_python_upper_bound() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -16300,6 +16503,7 @@ fn lock_python_upper_bound() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "magika", marker = "python_full_version < '3.13'" }] [[package]] @@ -16370,7 +16574,7 @@ fn lock_python_upper_bound() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/2a/14/e75e52d521442e2fcc9f1df3c5e456aead034203d4797867980de558ab34/tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9", size = 78296 }, ] - "### + "# ); }); @@ -16435,7 +16639,7 @@ fn lock_simplified_environments() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" resolution-markers = [ @@ -16468,8 +16672,9 @@ fn lock_simplified_environments() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -16544,7 +16749,7 @@ fn lock_dependency_metadata() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -16588,8 +16793,9 @@ fn lock_dependency_metadata() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] - "### + "# ); }); @@ -16749,7 +16955,7 @@ fn lock_dependency_metadata_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -16789,8 +16995,9 @@ fn lock_dependency_metadata_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", git = "https://github.com/agronholm/anyio?tag=4.6.2" }] - "### + "# ); }); @@ -16861,7 +17068,7 @@ fn lock_strip_fragment() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -16876,6 +17083,10 @@ fn lock_strip_fragment() -> Result<()> { { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -16885,8 +17096,9 @@ fn lock_strip_fragment() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }] - "### + "# ); }); @@ -17260,7 +17472,7 @@ fn lock_change_requires_python() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -17322,6 +17534,7 @@ fn lock_change_requires_python() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version == '3.12.*'", specifier = "<3" }, { name = "anyio", marker = "python_full_version >= '3.13'", specifier = ">3,<4" }, @@ -17335,7 +17548,7 @@ fn lock_change_requires_python() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -17369,7 +17582,7 @@ fn lock_change_requires_python() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10" resolution-markers = [ @@ -17432,6 +17645,7 @@ fn lock_change_requires_python() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "anyio", marker = "python_full_version == '3.12.*'", specifier = "<3" }, { name = "anyio", marker = "python_full_version >= '3.13'", specifier = ">3" }, @@ -17445,7 +17659,7 @@ fn lock_change_requires_python() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -17513,7 +17727,7 @@ fn lock_keyring_credentials() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -17529,6 +17743,7 @@ fn lock_keyring_credentials() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -17539,7 +17754,7 @@ fn lock_keyring_credentials() -> Result<()> { wheels = [ { url = "https://pypi-proxy.fly.dev/basic-auth/files/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -17582,7 +17797,7 @@ fn lock_multiple_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -17602,6 +17817,10 @@ fn lock_multiple_sources() -> Result<()> { ] sdist = { hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -17613,6 +17832,10 @@ fn lock_multiple_sources() -> Result<()> { { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -17623,11 +17846,12 @@ fn lock_multiple_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", marker = "sys_platform != 'win32'", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }, { name = "iniconfig", marker = "sys_platform == 'win32'", url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz" }, ] - "### + "# ); }); @@ -17769,7 +17993,7 @@ fn lock_multiple_sources_index_disjoint_markers() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -17835,11 +18059,12 @@ fn lock_multiple_sources_index_disjoint_markers() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "jinja2", marker = "sys_platform != 'win32'", specifier = ">=3,<3.1.4", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124" }, { name = "jinja2", marker = "sys_platform == 'win32'", specifier = ">=3,<3.1.4", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118" }, ] - "### + "# ); }); @@ -17899,7 +18124,7 @@ fn lock_multiple_sources_index_mixed() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -17942,6 +18167,7 @@ fn lock_multiple_sources_index_mixed() -> Result<()> { ] [package.metadata] + provides-extras = ["i18n"] requires-dist = [ { name = "babel", marker = "extra == 'i18n'", specifier = ">=2.7" }, { name = "markupsafe", specifier = ">=2.0" }, @@ -17971,11 +18197,12 @@ fn lock_multiple_sources_index_mixed() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "jinja2", marker = "sys_platform != 'win32'", url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl" }, { name = "jinja2", marker = "sys_platform == 'win32'", specifier = ">=3,<3.1.4", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118" }, ] - "### + "# ); }); @@ -18069,7 +18296,7 @@ fn lock_multiple_sources_index_explicit() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -18158,11 +18385,12 @@ fn lock_multiple_sources_index_explicit() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "jinja2", marker = "sys_platform != 'win32'", specifier = ">=3" }, { name = "jinja2", marker = "sys_platform == 'win32'", specifier = ">=3", index = "https://test.pypi.org/simple" }, ] - "### + "# ); }); @@ -18214,7 +18442,7 @@ fn lock_multiple_sources_non_total() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -18248,6 +18476,10 @@ fn lock_multiple_sources_non_total() -> Result<()> { { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -18258,11 +18490,12 @@ fn lock_multiple_sources_non_total() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "iniconfig", marker = "sys_platform != 'darwin'" }, { name = "iniconfig", marker = "sys_platform == 'darwin'", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }, ] - "### + "# ); }); @@ -18314,7 +18547,7 @@ fn lock_multiple_sources_respect_marker() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -18339,8 +18572,9 @@ fn lock_multiple_sources_respect_marker() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", marker = "sys_platform == 'win32'" }] - "### + "# ); }); @@ -18395,7 +18629,7 @@ fn lock_multiple_sources_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -18410,6 +18644,10 @@ fn lock_multiple_sources_extra() -> Result<()> { { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "project" version = "0.1.0" @@ -18421,11 +18659,12 @@ fn lock_multiple_sources_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["cpu"] requires-dist = [ { name = "iniconfig", marker = "extra == 'cpu'", url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl" }, { name = "iniconfig", marker = "extra != 'cpu'" }, ] - "### + "# ); }); @@ -18822,7 +19061,7 @@ fn lock_group_include() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -18903,6 +19142,7 @@ fn lock_group_include() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "typing-extensions" }] [package.metadata.requires-dev] @@ -18964,7 +19204,7 @@ fn lock_group_include() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -19350,7 +19590,7 @@ fn lock_group_workspace() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -19393,6 +19633,7 @@ fn lock_group_workspace() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">1" }] [package.metadata.requires-dev] @@ -19461,6 +19702,7 @@ fn lock_group_workspace() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "child", editable = "child" }] [package.metadata.requires-dev] @@ -19499,7 +19741,7 @@ fn lock_group_workspace() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -19540,7 +19782,7 @@ fn lock_transitive_git() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -19556,6 +19798,7 @@ fn lock_transitive_git() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "c", git = "https://github.com/astral-sh/workspace-virtual-root-test?subdirectory=packages%2Fc&rev=fac39c8d4c5d0ef32744e2bb309bbe34a759fd46" }] [[package]] @@ -19604,7 +19847,7 @@ fn lock_transitive_git() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -19702,7 +19945,7 @@ fn lock_dynamic_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -19712,7 +19955,11 @@ fn lock_dynamic_version() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -19740,7 +19987,7 @@ fn lock_dynamic_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -19750,7 +19997,11 @@ fn lock_dynamic_version() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -19820,6 +20071,10 @@ fn lock_dynamic_version_dependencies() -> Result<()> { [[package]] name = "project" source = { editable = "." } + + [package.metadata] + provides-extras = [] + requires-dist = [] "### ); }); @@ -19858,6 +20113,10 @@ fn lock_dynamic_version_dependencies() -> Result<()> { [[package]] name = "project" source = { editable = "." } + + [package.metadata] + provides-extras = [] + requires-dist = [] "### ); }); @@ -20003,7 +20262,7 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20020,6 +20279,10 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { name = "dynamic" source = { editable = "dynamic" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -20039,11 +20302,12 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dynamic", editable = "dynamic" }, { name = "iniconfig", specifier = ">=2" }, ] - "### + "# ); }); @@ -20072,7 +20336,7 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20089,6 +20353,10 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { name = "dynamic" source = { editable = "dynamic" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -20108,11 +20376,12 @@ fn lock_dynamic_version_workspace_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dynamic", editable = "dynamic" }, { name = "iniconfig", specifier = ">=2" }, ] - "### + "# ); }); @@ -20189,7 +20458,7 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20200,6 +20469,10 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { name = "dynamic" source = { directory = "dynamic" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -20219,11 +20492,12 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dynamic", directory = "dynamic" }, { name = "iniconfig", specifier = ">=2" }, ] - "### + "# ); }); @@ -20252,7 +20526,7 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20263,6 +20537,10 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { name = "dynamic" source = { directory = "dynamic" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "iniconfig" version = "2.0.0" @@ -20282,11 +20560,12 @@ fn lock_dynamic_version_path_dependency() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dynamic", directory = "dynamic" }, { name = "iniconfig", specifier = ">=2" }, ] - "### + "# ); }); @@ -20351,7 +20630,7 @@ fn lock_dynamic_version_self_extra_hatchling() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20394,6 +20673,7 @@ fn lock_dynamic_version_self_extra_hatchling() -> Result<()> { ] [package.metadata] + provides-extras = ["all", "async"] requires-dist = [ { name = "anyio", marker = "extra == 'all'" }, { name = "anyio", marker = "extra == 'async'" }, @@ -20416,7 +20696,7 @@ fn lock_dynamic_version_self_extra_hatchling() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); @@ -20509,7 +20789,7 @@ fn lock_dynamic_version_self_extra_setuptools() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20552,6 +20832,7 @@ fn lock_dynamic_version_self_extra_setuptools() -> Result<()> { ] [package.metadata] + provides-extras = ["all", "async"] requires-dist = [ { name = "anyio", marker = "extra == 'async'" }, { name = "project", extras = ["async"], marker = "extra == 'all'" }, @@ -20574,7 +20855,7 @@ fn lock_dynamic_version_self_extra_setuptools() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); @@ -20659,7 +20940,7 @@ fn lock_dynamic_built_cache() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20669,7 +20950,11 @@ fn lock_dynamic_built_cache() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -20705,7 +20990,7 @@ fn lock_dynamic_built_cache() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -20715,7 +21000,11 @@ fn lock_dynamic_built_cache() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -20779,7 +21068,7 @@ fn lock_shared_build_dependency() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -20903,6 +21192,7 @@ fn lock_shared_build_dependency() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "libcst", specifier = ">=1.1.0" }] [[package]] @@ -20986,7 +21276,7 @@ fn lock_shared_build_dependency() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, ] - "### + "# ); }); @@ -21057,7 +21347,7 @@ fn lock_dynamic_to_static() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21067,7 +21357,11 @@ fn lock_dynamic_to_static() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21113,7 +21407,7 @@ fn lock_dynamic_to_static() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21124,7 +21418,11 @@ fn lock_dynamic_to_static() -> Result<()> { name = "project" version = "0.1.0" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21166,7 +21464,7 @@ fn lock_static_to_dynamic() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21177,7 +21475,11 @@ fn lock_static_to_dynamic() -> Result<()> { name = "project" version = "0.1.0" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21242,7 +21544,7 @@ fn lock_static_to_dynamic() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21252,7 +21554,11 @@ fn lock_static_to_dynamic() -> Result<()> { [[package]] name = "project" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21289,7 +21595,7 @@ fn lock_bump_static_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21300,7 +21606,11 @@ fn lock_bump_static_version() -> Result<()> { name = "project" version = "0.1.0" source = { virtual = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21342,7 +21652,7 @@ fn lock_bump_static_version() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21353,7 +21663,11 @@ fn lock_bump_static_version() -> Result<()> { name = "project" version = "0.2.0" source = { virtual = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); @@ -21687,7 +22001,7 @@ fn lock_relative_project() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21703,6 +22017,7 @@ fn lock_relative_project() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "typing-extensions" }] [[package]] @@ -21713,7 +22028,7 @@ fn lock_relative_project() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -21788,7 +22103,7 @@ fn lock_recursive_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21827,6 +22142,7 @@ fn lock_recursive_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["foo", "bar", "baz", "bop", "qux"] requires-dist = [ { name = "iniconfig", marker = "extra == 'foo'" }, { name = "project", extras = ["bar"], marker = "sys_platform == 'darwin' and extra == 'bop'" }, @@ -21834,7 +22150,7 @@ fn lock_recursive_extra() -> Result<()> { { name = "project", extras = ["bop"], marker = "python_full_version == '3.12.*' and extra == 'qux'" }, { name = "project", extras = ["foo"], marker = "extra == 'bar'" }, ] - "### + "# ); }); @@ -21925,7 +22241,7 @@ fn lock_no_build_static_metadata() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -21941,6 +22257,7 @@ fn lock_no_build_static_metadata() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -21951,7 +22268,7 @@ fn lock_no_build_static_metadata() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -22047,7 +22364,7 @@ fn lock_self_compatible() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22063,6 +22380,7 @@ fn lock_self_compatible() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "project" }, { name = "typing-extensions" }, @@ -22076,7 +22394,7 @@ fn lock_self_compatible() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -22146,7 +22464,7 @@ fn lock_self_exact() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22162,6 +22480,7 @@ fn lock_self_exact() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "project", specifier = "==0.1.0" }, { name = "typing-extensions" }, @@ -22175,7 +22494,7 @@ fn lock_self_exact() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -22278,7 +22597,7 @@ fn lock_self_extra_to_extra_compatible() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22294,6 +22613,7 @@ fn lock_self_extra_to_extra_compatible() -> Result<()> { ] [package.metadata] + provides-extras = ["foo"] requires-dist = [ { name = "project", extras = ["foo"], marker = "extra == 'foo'" }, { name = "typing-extensions" }, @@ -22307,7 +22627,7 @@ fn lock_self_extra_to_extra_compatible() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -22447,7 +22767,7 @@ fn lock_self_extra_compatible() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22463,6 +22783,7 @@ fn lock_self_extra_compatible() -> Result<()> { ] [package.metadata] + provides-extras = ["foo"] requires-dist = [ { name = "project", marker = "extra == 'foo'" }, { name = "typing-extensions" }, @@ -22476,7 +22797,7 @@ fn lock_self_extra_compatible() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -22579,7 +22900,7 @@ fn lock_self_marker_compatible() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22595,6 +22916,7 @@ fn lock_self_marker_compatible() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "project", marker = "sys_platform == 'win32'" }, { name = "typing-extensions" }, @@ -22608,7 +22930,7 @@ fn lock_self_marker_compatible() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -22710,7 +23032,7 @@ fn lock_split_on_windows() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -22726,6 +23048,7 @@ fn lock_split_on_windows() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "pyqt5-qt5" }] [[package]] @@ -22736,7 +23059,7 @@ fn lock_split_on_windows() -> Result<()> { { url = "https://files.pythonhosted.org/packages/40/dc/96d9d0ba0d13256343b53efffe8729f278e62409ab4c937bb22e70ab98ac/PyQt5_Qt5-5.15.13-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:92575a9e96a27c4ed67c56c7048ded7461a1655d5d21f0e05064664e6e9fcbdf", size = 38771962 }, { url = "https://files.pythonhosted.org/packages/c9/8b/4441c208c8ca29b50fab6467ebfa32b6401d16c5c915a031a48dc85dfa7a/PyQt5_Qt5-5.15.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:141859f2ffe04cc6c5db970e2b6ad9f98897805d886a14c52614e3799daab6d6", size = 36663754 }, ] - "### + "# ); }); @@ -22809,7 +23132,7 @@ fn lock_arm() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -22842,8 +23165,9 @@ fn lock_arm() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "numpy" }] - "### + "# ); }); @@ -22883,7 +23207,7 @@ fn lock_x86_64() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -22917,8 +23241,9 @@ fn lock_x86_64() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "numpy" }] - "### + "# ); }); @@ -22958,7 +23283,7 @@ fn lock_x86() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -22989,8 +23314,9 @@ fn lock_x86() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "numpy" }] - "### + "# ); }); @@ -23029,7 +23355,7 @@ fn lock_script() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -23069,7 +23395,7 @@ fn lock_script() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -23165,7 +23491,7 @@ fn lock_script_path() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -23200,6 +23526,7 @@ fn lock_script_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] [[package]] @@ -23228,7 +23555,7 @@ fn lock_script_path() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -23370,7 +23697,7 @@ fn lock_pytorch_cpu() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12.[X]" resolution-markers = [ @@ -23733,6 +24060,7 @@ fn lock_pytorch_cpu() -> Result<()> { ] [package.metadata] + provides-extras = ["cpu", "cu124"] requires-dist = [ { name = "jinja2", specifier = "<=3.1.4" }, { name = "numpy", specifier = "<=2.2.0" }, @@ -23947,7 +24275,7 @@ fn lock_pytorch_cpu() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); @@ -24021,7 +24349,7 @@ fn lock_pytorch_preferences() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10.0" resolution-markers = [ @@ -24284,6 +24612,7 @@ fn lock_pytorch_preferences() -> Result<()> { ] [package.metadata] + provides-extras = ["cpu", "cu118"] requires-dist = [ { name = "torch", marker = "sys_platform == 'darwin' and extra == 'cpu'", specifier = "==2.2.2" }, { name = "torch", marker = "sys_platform == 'darwin' and extra == 'cu118'", specifier = "==2.2.2" }, @@ -24444,7 +24773,7 @@ fn lock_pytorch_preferences() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - "### + "# ); }); diff --git a/crates/uv/tests/it/lock_conflict.rs b/crates/uv/tests/it/lock_conflict.rs index 80ddc4c3e875b..606716cc3a573 100644 --- a/crates/uv/tests/it/lock_conflict.rs +++ b/crates/uv/tests/it/lock_conflict.rs @@ -89,7 +89,7 @@ fn extra_basic() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -114,6 +114,7 @@ fn extra_basic() -> Result<()> { ] [package.metadata] + provides-extras = ["extra1", "extra2"] requires-dist = [ { name = "sortedcontainers", marker = "extra == 'extra1'", specifier = "==2.3.0" }, { name = "sortedcontainers", marker = "extra == 'extra2'", specifier = "==2.4.0" }, @@ -136,7 +137,7 @@ fn extra_basic() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -281,7 +282,7 @@ fn extra_basic_three_extras() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -310,6 +311,7 @@ fn extra_basic_three_extras() -> Result<()> { ] [package.metadata] + provides-extras = ["extra1", "extra2", "project3"] requires-dist = [ { name = "sortedcontainers", marker = "extra == 'extra1'", specifier = "==2.2.0" }, { name = "sortedcontainers", marker = "extra == 'extra2'", specifier = "==2.3.0" }, @@ -342,7 +344,7 @@ fn extra_basic_three_extras() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -754,7 +756,7 @@ fn extra_multiple_independent() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -823,6 +825,7 @@ fn extra_multiple_independent() -> Result<()> { ] [package.metadata] + provides-extras = ["extra1", "extra2", "project3", "project4"] requires-dist = [ { name = "anyio", marker = "extra == 'project3'", specifier = "==4.1.0" }, { name = "anyio", marker = "extra == 'project4'", specifier = "==4.2.0" }, @@ -856,7 +859,7 @@ fn extra_multiple_independent() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -902,7 +905,7 @@ fn extra_config_change_ignore_lockfile() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -927,6 +930,7 @@ fn extra_config_change_ignore_lockfile() -> Result<()> { ] [package.metadata] + provides-extras = ["extra1", "extra2"] requires-dist = [ { name = "sortedcontainers", marker = "extra == 'extra1'", specifier = "==2.3.0" }, { name = "sortedcontainers", marker = "extra == 'extra2'", specifier = "==2.4.0" }, @@ -949,7 +953,7 @@ fn extra_config_change_ignore_lockfile() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -1715,7 +1719,7 @@ fn group_basic() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -1740,6 +1744,8 @@ fn group_basic() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] group1 = [{ name = "sortedcontainers", specifier = "==2.3.0" }] @@ -1762,7 +1768,7 @@ fn group_basic() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -1869,7 +1875,7 @@ fn group_default() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -1894,6 +1900,8 @@ fn group_default() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] group1 = [{ name = "sortedcontainers", specifier = "==2.3.0" }] @@ -1916,7 +1924,7 @@ fn group_default() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -2080,7 +2088,7 @@ fn mixed() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -2107,6 +2115,7 @@ fn mixed() -> Result<()> { ] [package.metadata] + provides-extras = ["extra1"] requires-dist = [{ name = "sortedcontainers", marker = "extra == 'extra1'", specifier = "==2.4.0" }] [package.metadata.requires-dev] @@ -2129,7 +2138,7 @@ fn mixed() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -2248,7 +2257,7 @@ fn multiple_sources_index_disjoint_extras() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -2316,11 +2325,12 @@ fn multiple_sources_index_disjoint_extras() -> Result<()> { ] [package.metadata] + provides-extras = ["cu118", "cu124"] requires-dist = [ { name = "jinja2", marker = "extra == 'cu118'", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", extra = "cu118" } }, { name = "jinja2", marker = "extra == 'cu124'", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", extra = "cu124" } }, ] - "### + "# ); }); @@ -2396,7 +2406,7 @@ fn multiple_sources_index_disjoint_groups() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -2464,11 +2474,13 @@ fn multiple_sources_index_disjoint_groups() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] cu118 = [{ name = "jinja2", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", group = "cu118" } }] cu124 = [{ name = "jinja2", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", group = "cu124" } }] - "### + "# ); }); @@ -2544,7 +2556,7 @@ fn multiple_sources_index_disjoint_extras_with_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -2631,11 +2643,12 @@ fn multiple_sources_index_disjoint_extras_with_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["cu118", "cu124"] requires-dist = [ { name = "jinja2", extras = ["i18n"], marker = "extra == 'cu118'", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", extra = "cu118" } }, { name = "jinja2", extras = ["i18n"], marker = "extra == 'cu124'", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", extra = "cu124" } }, ] - "### + "# ); }); @@ -2711,7 +2724,7 @@ fn multiple_sources_index_disjoint_extras_with_marker() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -2804,12 +2817,13 @@ fn multiple_sources_index_disjoint_extras_with_marker() -> Result<()> { ] [package.metadata] + provides-extras = ["cu118", "cu124"] requires-dist = [ { name = "jinja2", marker = "sys_platform == 'darwin' and extra == 'cu118'", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", extra = "cu118" } }, { name = "jinja2", marker = "sys_platform != 'darwin' and extra == 'cu118'", specifier = "==3.1.2" }, { name = "jinja2", marker = "extra == 'cu124'", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", extra = "cu124" } }, ] - "### + "# ); }); @@ -3035,7 +3049,7 @@ fn shared_optional_dependency_extra1() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -3095,6 +3109,7 @@ fn shared_optional_dependency_extra1() -> Result<()> { ] [package.metadata] + provides-extras = ["foo", "bar", "baz"] requires-dist = [ { name = "anyio", marker = "extra == 'baz'" }, { name = "idna", marker = "extra == 'bar'", specifier = "==3.6" }, @@ -3109,7 +3124,7 @@ fn shared_optional_dependency_extra1() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3173,7 +3188,7 @@ fn shared_optional_dependency_group1() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -3233,6 +3248,8 @@ fn shared_optional_dependency_group1() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] bar = [{ name = "idna", specifier = "==3.6" }] @@ -3247,7 +3264,7 @@ fn shared_optional_dependency_group1() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3313,7 +3330,7 @@ fn shared_optional_dependency_mixed1() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -3375,6 +3392,7 @@ fn shared_optional_dependency_mixed1() -> Result<()> { ] [package.metadata] + provides-extras = ["foo"] requires-dist = [{ name = "idna", marker = "extra == 'foo'", specifier = "==3.5" }] [package.metadata.requires-dev] @@ -3389,7 +3407,7 @@ fn shared_optional_dependency_mixed1() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3456,7 +3474,7 @@ fn shared_optional_dependency_extra2() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" conflicts = [[ @@ -3515,6 +3533,7 @@ fn shared_optional_dependency_extra2() -> Result<()> { ] [package.metadata] + provides-extras = ["foo", "bar"] requires-dist = [ { name = "anyio", marker = "extra == 'bar'" }, { name = "anyio", marker = "extra == 'foo'" }, @@ -3530,7 +3549,7 @@ fn shared_optional_dependency_extra2() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3595,7 +3614,7 @@ fn shared_optional_dependency_group2() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" conflicts = [[ @@ -3654,6 +3673,8 @@ fn shared_optional_dependency_group2() -> Result<()> { ] [package.metadata] + provides-extras = [] + requires-dist = [] [package.metadata.requires-dev] bar = [ @@ -3673,7 +3694,7 @@ fn shared_optional_dependency_group2() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3740,7 +3761,7 @@ fn shared_optional_dependency_mixed2() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" conflicts = [[ @@ -3801,6 +3822,7 @@ fn shared_optional_dependency_mixed2() -> Result<()> { ] [package.metadata] + provides-extras = ["foo"] requires-dist = [ { name = "anyio", marker = "extra == 'foo'" }, { name = "idna", marker = "extra == 'foo'", specifier = "==3.5" }, @@ -3820,7 +3842,7 @@ fn shared_optional_dependency_mixed2() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -3882,7 +3904,7 @@ fn shared_dependency_extra() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -3942,6 +3964,7 @@ fn shared_dependency_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["foo", "bar"] requires-dist = [ { name = "anyio" }, { name = "idna", marker = "extra == 'bar'", specifier = "==3.6" }, @@ -3956,7 +3979,7 @@ fn shared_dependency_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -4055,7 +4078,7 @@ fn shared_dependency_group() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -4115,6 +4138,7 @@ fn shared_dependency_group() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio" }] [package.metadata.requires-dev] @@ -4129,7 +4153,7 @@ fn shared_dependency_group() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -4230,7 +4254,7 @@ fn shared_dependency_mixed() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -4292,6 +4316,7 @@ fn shared_dependency_mixed() -> Result<()> { ] [package.metadata] + provides-extras = ["foo"] requires-dist = [ { name = "anyio" }, { name = "idna", marker = "extra == 'foo'", specifier = "==3.5" }, @@ -4308,7 +4333,7 @@ fn shared_dependency_mixed() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -4415,11 +4440,18 @@ conflicts = [ "#, )?; - // I believe there are multiple valid solutions here, but the main - // thing is that `x2` should _not_ activate the `idna==3.4` dependency - // in `proxy1`. The `--extra=x2` should be a no-op, since there is no - // `x2` extra in the top level `pyproject.toml`. + // Error out, as x2 extra is only on the child. uv_snapshot!(context.filters(), context.sync().arg("--extra=x2"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 7 packages in [TIME] + error: Extra `x2` is not defined in the project's `optional-dependencies` table + "###); + + uv_snapshot!(context.filters(), context.sync(), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4438,7 +4470,7 @@ conflicts = [ filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = "==3.11.*" conflicts = [[ @@ -4513,6 +4545,7 @@ conflicts = [ ] [package.metadata] + provides-extras = ["x1"] requires-dist = [ { name = "anyio", specifier = ">=4" }, { name = "idna", marker = "extra == 'x1'", specifier = "==3.6" }, @@ -4533,6 +4566,7 @@ conflicts = [ ] [package.metadata] + provides-extras = ["x2", "x3"] requires-dist = [ { name = "idna", marker = "extra == 'x2'", specifier = "==3.4" }, { name = "idna", marker = "extra == 'x3'", specifier = "==3.5" }, @@ -4546,7 +4580,7 @@ conflicts = [ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "### + "# ); }); @@ -4621,7 +4655,7 @@ fn jinja_no_conflict_markers1() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -4708,11 +4742,12 @@ fn jinja_no_conflict_markers1() -> Result<()> { ] [package.metadata] + provides-extras = ["cu118", "cu124"] requires-dist = [ { name = "jinja2", extras = ["i18n"], marker = "extra == 'cu118'", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", extra = "cu118" } }, { name = "jinja2", extras = ["i18n"], marker = "extra == 'cu124'", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", extra = "cu124" } }, ] - "### + "# ); }); @@ -4781,7 +4816,7 @@ fn jinja_no_conflict_markers2() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -4874,12 +4909,13 @@ fn jinja_no_conflict_markers2() -> Result<()> { ] [package.metadata] + provides-extras = ["cu118", "cu124"] requires-dist = [ { name = "jinja2", marker = "sys_platform == 'darwin' and extra == 'cu118'", specifier = "==3.1.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu118", conflict = { package = "project", extra = "cu118" } }, { name = "jinja2", marker = "sys_platform != 'darwin' and extra == 'cu118'", specifier = "==3.1.2" }, { name = "jinja2", marker = "extra == 'cu124'", specifier = "==3.1.3", index = "https://astral-sh.github.io/pytorch-mirror/whl/cu124", conflict = { package = "project", extra = "cu124" } }, ] - "### + "# ); }); @@ -4940,7 +4976,7 @@ fn collision_extra() -> Result<()> { }, { assert_snapshot!( lock, - @r###" + @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -5003,6 +5039,7 @@ fn collision_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["foo", "bar", "extra-3-pkg-foo"] requires-dist = [ { name = "anyio" }, { name = "idna", marker = "extra == 'bar'", specifier = "==3.6" }, @@ -5027,7 +5064,7 @@ fn collision_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] - "### + "# ); }); @@ -5167,7 +5204,7 @@ fn extra_inferences() -> Result<()> { }, { assert_snapshot!( lock, - @r###" + @r#" version = 1 requires-python = ">=3.12" conflicts = [[ @@ -6539,6 +6576,7 @@ fn extra_inferences() -> Result<()> { ] [package.metadata] + provides-extras = ["x1", "x2"] requires-dist = [ { name = "apache-airflow", marker = "extra == 'x1'", specifier = "==2.5.0" }, { name = "apache-airflow", marker = "extra == 'x2'", specifier = "==2.6.0" }, @@ -7128,7 +7166,7 @@ fn extra_inferences() -> Result<()> { { url = "https://files.pythonhosted.org/packages/c5/f4/2fdc5a11503bc61818243653d836061c9ce0370e2dd9ac5917258a007675/yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984", size = 76397 }, { url = "https://files.pythonhosted.org/packages/4d/05/4d79198ae568a92159de0f89e710a8d19e3fa267b719a236582eee921f4a/yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad", size = 31638 }, ] - "### + "# ); }); @@ -7201,7 +7239,7 @@ fn deduplicate_resolution_markers() -> Result<()> { }, { assert_snapshot!( lock, - @r###" + @r#" version = 1 requires-python = ">=3.12" resolution-markers = [ @@ -7277,13 +7315,14 @@ fn deduplicate_resolution_markers() -> Result<()> { ] [package.metadata] + provides-extras = ["x1", "x2"] requires-dist = [ { name = "idna", marker = "sys_platform == 'linux' and extra == 'x1'", specifier = "==3.6" }, { name = "idna", marker = "sys_platform != 'linux' and extra == 'x1'", specifier = "==3.5" }, { name = "markupsafe", marker = "sys_platform == 'linux' and extra == 'x2'", specifier = "==2.1.0" }, { name = "markupsafe", marker = "sys_platform != 'linux' and extra == 'x2'", specifier = "==2.0.0" }, ] - "### + "# ); }); @@ -7353,7 +7392,7 @@ fn incorrect_extra_simplification_leads_to_multiple_torch_packages() -> Result<( }, { assert_snapshot!( lock, - @r###" + @r#" version = 1 requires-python = ">=3.10" resolution-markers = [ @@ -9695,6 +9734,7 @@ fn incorrect_extra_simplification_leads_to_multiple_torch_packages() -> Result<( ] [package.metadata] + provides-extras = ["chgnet", "m3gnet"] requires-dist = [ { name = "chgnet", marker = "extra == 'chgnet'", specifier = "==0.4.0" }, { name = "mace-torch", specifier = "==0.3.9" }, @@ -10028,7 +10068,7 @@ fn incorrect_extra_simplification_leads_to_multiple_torch_packages() -> Result<( { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723 }, { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, ] - "### + "# ); }); @@ -10093,7 +10133,7 @@ fn overlapping_resolution_markers() -> Result<()> { }, { assert_snapshot!( lock, - @r###" + @r#" version = 1 requires-python = "==3.10.*" resolution-markers = [ @@ -10133,6 +10173,7 @@ fn overlapping_resolution_markers() -> Result<()> { ] [package.metadata] + provides-extras = ["cpu", "cu118"] requires-dist = [ { name = "torch", marker = "sys_platform == 'darwin' and extra == 'cpu'", specifier = "==2.2.2" }, { name = "torch", marker = "sys_platform != 'darwin' and extra == 'cpu'", specifier = "==2.2.2", index = "https://astral-sh.github.io/pytorch-mirror/whl/cpu", conflict = { package = "ads-mega-model", extra = "cpu" } }, @@ -10702,7 +10743,7 @@ fn overlapping_resolution_markers() -> Result<()> { { url = "https://files.pythonhosted.org/packages/df/b9/1d26752a7c9ff5b255c921e13a9c5176e21a0b77e53d3febf892d90c86a5/wandb-0.17.6-py3-none-win32.whl", hash = "sha256:247b1c9677fd633a460201f421d4fd4f370e7243d06257fab0ad1bb728ddcc1c", size = 6504208 }, { url = "https://files.pythonhosted.org/packages/fc/2c/280b8891362967e54de2267454ac6033568b8412ec31225f00ecc11db7a6/wandb-0.17.6-py3-none-win_amd64.whl", hash = "sha256:51954f993b372c20812616838302183f0e3abf137614f05d80c7c17c307bfff9", size = 6504213 }, ] - "### + "# ); }); diff --git a/crates/uv/tests/it/lock_scenarios.rs b/crates/uv/tests/it/lock_scenarios.rs index b9f031588f5f1..dc66d1ee8aa4d 100644 --- a/crates/uv/tests/it/lock_scenarios.rs +++ b/crates/uv/tests/it/lock_scenarios.rs @@ -121,7 +121,7 @@ fn wrong_backtracking_basic() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -135,6 +135,7 @@ fn wrong_backtracking_basic() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a" }, { name = "package-b" }, @@ -160,7 +161,7 @@ fn wrong_backtracking_basic() -> Result<()> { wheels = [ { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/wrong_backtracking_basic_b-2.0.9-py3-none-any.whl", hash = "sha256:bf96af1a69f8c1d1d9c2687cd5d6f023cda56dd77d3f37f3cdd422e2a410541f" }, ] - "### + "# ); }); @@ -244,7 +245,7 @@ fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -271,11 +272,12 @@ fn fork_allows_non_conflicting_non_overlapping_dependencies() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=1" }, ] - "### + "# ); }); @@ -361,7 +363,7 @@ fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -383,11 +385,12 @@ fn fork_allows_non_conflicting_repeated_dependencies() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", specifier = "<2" }, { name = "package-a", specifier = ">=1" }, ] - "### + "# ); }); @@ -460,7 +463,7 @@ fn fork_basic() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -503,11 +506,12 @@ fn fork_basic() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -745,7 +749,7 @@ fn fork_filter_sibling_dependencies() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -838,13 +842,14 @@ fn fork_filter_sibling_dependencies() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "==4.3.0" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = "==4.4.0" }, { name = "package-b", marker = "sys_platform == 'linux'", specifier = "==1.0.0" }, { name = "package-c", marker = "sys_platform == 'darwin'", specifier = "==1.0.0" }, ] - "### + "# ); }); @@ -923,7 +928,7 @@ fn fork_upgrade() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -957,8 +962,9 @@ fn fork_upgrade() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-foo" }] - "### + "# ); }); @@ -1043,7 +1049,7 @@ fn fork_incomplete_markers() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -1108,12 +1114,13 @@ fn fork_incomplete_markers() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "python_full_version < '3.10'", specifier = "==1" }, { name = "package-a", marker = "python_full_version >= '3.11'", specifier = "==2" }, { name = "package-b" }, ] - "### + "# ); }); @@ -1196,7 +1203,7 @@ fn fork_marker_accrue() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -1243,11 +1250,12 @@ fn fork_marker_accrue() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "implementation_name == 'cpython'", specifier = "==1.0.0" }, { name = "package-b", marker = "implementation_name == 'pypy'", specifier = "==1.0.0" }, ] - "### + "# ); }); @@ -1399,7 +1407,7 @@ fn fork_marker_inherit_combined_allowed() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -1486,11 +1494,12 @@ fn fork_marker_inherit_combined_allowed() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -1579,7 +1588,7 @@ fn fork_marker_inherit_combined_disallowed() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -1654,11 +1663,12 @@ fn fork_marker_inherit_combined_disallowed() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -1748,7 +1758,7 @@ fn fork_marker_inherit_combined() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -1823,11 +1833,12 @@ fn fork_marker_inherit_combined() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -1910,7 +1921,7 @@ fn fork_marker_inherit_isolated() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -1965,11 +1976,12 @@ fn fork_marker_inherit_isolated() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -2058,7 +2070,7 @@ fn fork_marker_inherit_transitive() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -2125,11 +2137,12 @@ fn fork_marker_inherit_transitive() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -2214,7 +2227,7 @@ fn fork_marker_inherit() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -2257,11 +2270,12 @@ fn fork_marker_inherit() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -2352,7 +2366,7 @@ fn fork_marker_limited_inherit() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -2417,12 +2431,13 @@ fn fork_marker_limited_inherit() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'linux'", specifier = ">=2" }, { name = "package-b" }, ] - "### + "# ); }); @@ -2507,7 +2522,7 @@ fn fork_marker_selection() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -2560,12 +2575,13 @@ fn fork_marker_selection() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a" }, { name = "package-b", marker = "sys_platform == 'darwin'", specifier = "<2" }, { name = "package-b", marker = "sys_platform == 'linux'", specifier = ">=2" }, ] - "### + "# ); }); @@ -2662,7 +2678,7 @@ fn fork_marker_track() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -2727,12 +2743,13 @@ fn fork_marker_track() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a" }, { name = "package-b", marker = "sys_platform == 'darwin'", specifier = "<2.8" }, { name = "package-b", marker = "sys_platform == 'linux'", specifier = ">=2.8" }, ] - "### + "# ); }); @@ -2814,7 +2831,7 @@ fn fork_non_fork_marker_transitive() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -2861,11 +2878,12 @@ fn fork_non_fork_marker_transitive() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", specifier = "==1.0.0" }, { name = "package-b", specifier = "==1.0.0" }, ] - "### + "# ); }); @@ -3113,7 +3131,7 @@ fn fork_overlapping_markers_basic() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -3140,12 +3158,13 @@ fn fork_overlapping_markers_basic() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "python_full_version < '3.10'", specifier = ">=1.0.0" }, { name = "package-a", marker = "python_full_version >= '3.10'", specifier = ">=1.1.0" }, { name = "package-a", marker = "python_full_version >= '3.11'", specifier = ">=1.2.0" }, ] - "### + "# ); }); @@ -3280,7 +3299,7 @@ fn preferences_dependent_forking_bistable() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -3384,8 +3403,9 @@ fn preferences_dependent_forking_bistable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-cleaver" }] - "### + "# ); }); @@ -3658,7 +3678,7 @@ fn preferences_dependent_forking_tristable() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -3806,12 +3826,13 @@ fn preferences_dependent_forking_tristable() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-bar" }, { name = "package-cleaver" }, { name = "package-foo" }, ] - "### + "# ); }); @@ -3941,7 +3962,7 @@ fn preferences_dependent_forking() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -4007,12 +4028,13 @@ fn preferences_dependent_forking() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-bar" }, { name = "package-cleaver" }, { name = "package-foo" }, ] - "### + "# ); }); @@ -4115,7 +4137,7 @@ fn fork_remaining_universe_partitioning() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" resolution-markers = [ @@ -4190,11 +4212,12 @@ fn fork_remaining_universe_partitioning() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'illumos'", specifier = "<2" }, { name = "package-a", marker = "sys_platform == 'windows'", specifier = ">=2" }, ] - "### + "# ); }); @@ -4277,6 +4300,7 @@ fn fork_requires_python_full_prerelease() -> Result<()> { source = { virtual = "." } [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9'", specifier = "==1.0.0" }] "### ); @@ -4361,6 +4385,7 @@ fn fork_requires_python_full() -> Result<()> { source = { virtual = "." } [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9'", specifier = "==1.0.0" }] "### ); @@ -4439,7 +4464,7 @@ fn fork_requires_python_patch_overlap() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10.1" @@ -4461,8 +4486,9 @@ fn fork_requires_python_patch_overlap() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", marker = "python_full_version == '3.10.*'", specifier = "==1.0.0" }] - "### + "# ); }); @@ -4542,6 +4568,7 @@ fn fork_requires_python() -> Result<()> { source = { virtual = "." } [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", marker = "python_full_version == '3.9.*'", specifier = "==1.0.0" }] "### ); @@ -4612,7 +4639,7 @@ fn requires_python_wheels() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.10" @@ -4625,6 +4652,7 @@ fn requires_python_wheels() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", specifier = "==1.0.0" }] [[package]] @@ -4636,7 +4664,7 @@ fn requires_python_wheels() -> Result<()> { { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/requires_python_wheels_a-1.0.0-cp310-cp310-any.whl", hash = "sha256:b979494a0d7dc825b84d6c516ac407143915f6d2840d229ee2a36b3d06deb61d" }, { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/requires_python_wheels_a-1.0.0-cp311-cp311-any.whl", hash = "sha256:b979494a0d7dc825b84d6c516ac407143915f6d2840d229ee2a36b3d06deb61d" }, ] - "### + "# ); }); @@ -4708,7 +4736,7 @@ fn unreachable_package() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -4721,6 +4749,7 @@ fn unreachable_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a", marker = "sys_platform == 'win32'", specifier = "==1.0.0" }] [[package]] @@ -4731,7 +4760,7 @@ fn unreachable_package() -> Result<()> { wheels = [ { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_package_a-1.0.0-py3-none-any.whl", hash = "sha256:cc472ded9f3b260e6cda0e633fa407a13607e190422cb455f02beebd32d6751f" }, ] - "### + "# ); }); @@ -4809,7 +4838,7 @@ fn unreachable_wheels() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -4824,6 +4853,7 @@ fn unreachable_wheels() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "package-a", marker = "sys_platform == 'win32'", specifier = "==1.0.0" }, { name = "package-b", marker = "sys_platform == 'linux'", specifier = "==1.0.0" }, @@ -4857,7 +4887,7 @@ fn unreachable_wheels() -> Result<()> { wheels = [ { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/unreachable_wheels_c-1.0.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4b846c5b1646b04828a2bef6c9d180ff7cfd725866013dcec8933de7fb5f9e8d" }, ] - "### + "# ); }); @@ -4937,7 +4967,7 @@ fn specific_architecture() -> Result<()> { filters => filters, }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.8" @@ -4950,6 +4980,7 @@ fn specific_architecture() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package-a" }] [[package]] @@ -4997,7 +5028,7 @@ fn specific_architecture() -> Result<()> { { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_d-1.0.0-cp313-cp313-freebsd_13_x86_64.whl", hash = "sha256:842864c1348694fab33199eb05921602c2abfc77844a81085a55db02edd30da4" }, { url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/specific_architecture_d-1.0.0-cp313-cp313-manylinux2010_i686.whl", hash = "sha256:842864c1348694fab33199eb05921602c2abfc77844a81085a55db02edd30da4" }, ] - "### + "# ); }); diff --git a/crates/uv/tests/it/pip_compile.rs b/crates/uv/tests/it/pip_compile.rs index f7d62c222f385..4b12871f69e43 100644 --- a/crates/uv/tests/it/pip_compile.rs +++ b/crates/uv/tests/it/pip_compile.rs @@ -1309,6 +1309,89 @@ fn compile_python_312() -> Result<()> { "### ); + // This should work with the short flag + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("-p") + .arg("3.12"), @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.in -p 3.12 + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // And `--python` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python") + .arg("3.12"), @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.in --python 3.12 + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // And `UV_PYTHON` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .env("UV_PYTHON", "3.12"), @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.in + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + Ok(()) } @@ -1347,7 +1430,7 @@ fn compile_python_312_annotation_line() -> Result<()> { /// Compile for 3.12 when only a different interpreter version is available. #[test] fn compile_fallback_interpreter() -> Result<()> { - let context = TestContext::new("3.10"); + let context = TestContext::new("3.10").with_filtered_python_sources(); let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("black==23.10.1")?; @@ -1379,6 +1462,400 @@ fn compile_fallback_interpreter() -> Result<()> { "### ); + // This should work for the short flag too + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("-p") + .arg("3.12"), @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.in -p 3.12 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + warning: The requested Python version 3.12 is not available; 3.10.[X] will be used to build dependencies instead. + Resolved 6 packages in [TIME] + "### + ); + + // And for `UV_PYTHON` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .env(EnvVars::UV_PYTHON, "3.12"), @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.in + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + warning: The requested Python version 3.12 is not available; 3.10.[X] will be used to build dependencies instead. + Resolved 6 packages in [TIME] + "### + ); + + // And for `--python` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python") + .arg("3.12"), @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.in --python 3.12 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + warning: The requested Python version 3.12 is not available; 3.10.[X] will be used to build dependencies instead. + Resolved 6 packages in [TIME] + "### + ); + + // We also allow requesting alternative implementations, but we should fail if we can't find it + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("-p") + .arg("pypy"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found for PyPy in [PYTHON SOURCES] + "### + ); + + // Similarly, we fail if we receive a range request that cannot be satisfied + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("-p") + .arg(">=3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found for Python >=3.12 in [PYTHON SOURCES] + "### + ); + + Ok(()) +} + +#[test] +fn compile_python_conflicts() -> Result<()> { + let context = TestContext::new("3.12"); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("black==23.10.1")?; + + // `-p` and `--python` cannot be used together + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python") + .arg("3.12") + .arg("-p") + .arg("3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the argument '--python ' cannot be used multiple times + + Usage: uv pip compile [OPTIONS] ... + + For more information, try '--help'. + "### + ); + + // `UV_PYTHON` should be usable with `-p` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("-p") + .arg("3.12") + .env("UV_PYTHON", "3.11"), @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.in -p 3.12 + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // `UV_PYTHON` should be usable with `--python` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python") + .arg("3.12") + .env("UV_PYTHON", "3.11"), @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.in --python 3.12 + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // `UV_PYTHON` should be usable with `--python-version` + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .env("UV_PYTHON", "3.11"), @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.in --python-version 3.12 + black==23.10.1 + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + Ok(()) +} + +#[test] +fn compile_python_build_version_different_than_target() -> Result<()> { + let context = + TestContext::new_with_versions(&["3.12", "3.10", "3.11"]).with_filtered_python_sources(); + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("black==23.10.1")?; + + // The build interpreter can differ from the target version + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .arg("-p") + .arg("3.11") + .env_remove(EnvVars::VIRTUAL_ENV), @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.in --python-version 3.12 -p 3.11 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .arg("-p") + .arg("cpython@3.11") + .env_remove(EnvVars::VIRTUAL_ENV), @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.in --python-version 3.12 -p cpython@3.11 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // If we can't find the interpreter, we fail + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .arg("-p") + .arg("pypy@3.11") + .env_remove(EnvVars::VIRTUAL_ENV), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found for PyPy 3.11 in [PYTHON SOURCES] + "### + ); + + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .arg("-p") + .arg("3.13") + .env_remove(EnvVars::VIRTUAL_ENV), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found for Python 3.13 in [PYTHON SOURCES] + "### + ); + + // `UV_PYTHON` is ignored if `--python-version` is set + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .env(EnvVars::UV_PYTHON, "3.11") + .env_remove(EnvVars::VIRTUAL_ENV), @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.in --python-version 3.12 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + + // `UV_PYTHON` is ignored if `--python-version` is set + uv_snapshot!(context.filters(), context.pip_compile() + .arg("requirements.in") + .arg("--python-version") + .arg("3.12") + .env(EnvVars::UV_PYTHON, "pypy") + .env_remove(EnvVars::VIRTUAL_ENV), @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.in --python-version 3.12 + black==23.10.[X] + # via -r requirements.in + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==24.0 + # via black + pathspec==0.12.1 + # via black + platformdirs==4.2.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "### + ); + Ok(()) } @@ -13824,8 +14301,8 @@ fn lowest_fork_min_python() -> Result<()> { let context = TestContext::new("3.10"); let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str(indoc::indoc! {r" - pycountry >= 22.1.10 - setuptools >= 50.0.0 ; python_version >= '3.12' + anyio >= 3.0.0 + idna >= 3.0.0 ; python_version >= '3.12' "})?; uv_snapshot!(context.filters(), windows_filters=false, context.pip_compile() @@ -13838,20 +14315,21 @@ fn lowest_fork_min_python() -> Result<()> { ----- stdout ----- # This file was autogenerated by uv via the following command: # uv pip compile --cache-dir [CACHE_DIR] requirements.in --universal --resolution lowest - pycountry==22.1.10 + anyio==3.0.0 # via -r requirements.in - setuptools==0.7.2 ; python_full_version < '3.12' + idna==2.8 ; python_full_version < '3.12' # via # -r requirements.in - # pycountry - setuptools==50.0.0 ; python_full_version >= '3.12' + # anyio + idna==3.0 ; python_full_version >= '3.12' # via # -r requirements.in - # pycountry + # anyio + sniffio==1.1.0 + # via anyio ----- stderr ----- - Resolved 3 packages in [TIME] - warning: The transitive dependency `setuptools` is unpinned. Consider setting a lower bound with a constraint when using `--resolution lowest` to avoid using outdated versions. + Resolved 4 packages in [TIME] "### ); diff --git a/crates/uv/tests/it/publish.rs b/crates/uv/tests/it/publish.rs index 32f2419248e2c..ae33eea84d075 100644 --- a/crates/uv/tests/it/publish.rs +++ b/crates/uv/tests/it/publish.rs @@ -23,7 +23,6 @@ fn username_password_no_longer_supported() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/ Uploading ok-1.0.0-py3-none-any.whl ([SIZE]) error: Failed to publish `../../scripts/links/ok-1.0.0-py3-none-any.whl` to https://test.pypi.org/legacy/ @@ -49,7 +48,6 @@ fn invalid_token() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/ Uploading ok-1.0.0-py3-none-any.whl ([SIZE]) error: Failed to publish `../../scripts/links/ok-1.0.0-py3-none-any.whl` to https://test.pypi.org/legacy/ @@ -82,7 +80,6 @@ fn mixed_credentials() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/ error: a username and a password are not allowed when using trusted publishing "### @@ -109,7 +106,6 @@ fn missing_trusted_publishing_permission() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/ error: Failed to obtain token for trusted publishing Caused by: Environment variable ACTIONS_ID_TOKEN_REQUEST_TOKEN not set, is the `id-token: write` permission missing? @@ -136,7 +132,6 @@ fn no_credentials() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/ Note: Neither credentials nor keyring are configured, and there was an error fetching the trusted publishing token. If you don't want to use trusted publishing, you can ignore this error, but you need to provide credentials. Trusted publishing error: Environment variable ACTIONS_ID_TOKEN_REQUEST_TOKEN not set, is the `id-token: write` permission missing? @@ -162,7 +157,6 @@ fn skip_existing_redirect() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning error: `uv publish` does not support `--skip-existing` because there is not a reliable way to identify when an upload fails due to an existing distribution. Instead, use `--check-url` to provide the URL to the simple API for your index. uv will check the index for existing distributions before attempting uploads. "### ); @@ -193,7 +187,6 @@ fn dubious_filenames() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning warning: Skipping file that looks like a distribution, but is not a valid distribution filename: `[TEMP_DIR]/data.tar.gz` warning: Skipping file that looks like a distribution, but is not a valid distribution filename: `[TEMP_DIR]/not-a-wheel.whl` warning: Skipping file that looks like a distribution, but is not a valid distribution filename: `[TEMP_DIR]/not-sdist-1-2-3-asdf.zip` @@ -239,7 +232,6 @@ fn check_keyring_behaviours() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/?ok Uploading ok-1.0.0-py3-none-any.whl ([SIZE]) error: Failed to publish `../../scripts/links/ok-1.0.0-py3-none-any.whl` to https://test.pypi.org/legacy/?ok @@ -264,7 +256,6 @@ fn check_keyring_behaviours() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/?ok warning: Using `--keyring-provider` with a password or token and no check URL has no effect Uploading ok-1.0.0-py3-none-any.whl ([SIZE]) @@ -291,7 +282,6 @@ fn check_keyring_behaviours() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/?ok Request for dummy@https://test.pypi.org/legacy/?ok Request for dummy@test.pypi.org @@ -321,7 +311,6 @@ fn check_keyring_behaviours() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning Publishing 1 file to https://test.pypi.org/legacy/?ok Request for dummy@https://test.pypi.org/legacy/?ok Uploading ok-1.0.0-py3-none-any.whl ([SIZE]) @@ -374,7 +363,6 @@ fn invalid_index() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning error: Index not found: `bar`. Found indexes: `foo`, `internal` "### ); @@ -394,7 +382,6 @@ fn invalid_index() { ----- stdout ----- ----- stderr ----- - warning: `uv publish` is experimental and may change without warning error: Index is missing a publish URL: `foo` "### ); diff --git a/crates/uv/tests/it/python_install.rs b/crates/uv/tests/it/python_install.rs index 345dba5e62f70..aedcc399f50e3 100644 --- a/crates/uv/tests/it/python_install.rs +++ b/crates/uv/tests/it/python_install.rs @@ -1,13 +1,13 @@ use std::{path::Path, process::Command}; +use crate::common::{uv_snapshot, TestContext}; use assert_fs::{ assert::PathAssert, prelude::{FileTouch, PathChild, PathCreateDir}, }; use predicates::prelude::predicate; use uv_fs::Simplified; - -use crate::common::{uv_snapshot, TestContext}; +use uv_static::EnvVars; #[test] fn python_install() { @@ -1058,9 +1058,96 @@ fn python_install_preview_broken_link() { }); } +#[test] +fn python_install_default_from_env() { + let context: TestContext = TestContext::new_with_versions(&[]) + .with_filtered_python_keys() + .with_filtered_exe_suffix() + .with_managed_python_dirs(); + + // Install the version specified by the `UV_PYTHON` environment variable by default + uv_snapshot!(context.filters(), context.python_install().env(EnvVars::UV_PYTHON, "3.12"), @r" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Installed Python 3.12.9 in [TIME] + + cpython-3.12.9-[PLATFORM] + "); + + // But prefer explicit requests + uv_snapshot!(context.filters(), context.python_install().arg("3.11").env(EnvVars::UV_PYTHON, "3.12"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Installed Python 3.11.11 in [TIME] + + cpython-3.11.11-[PLATFORM] + "###); + + // We should ignore `UV_PYTHON` here and complain there is not a target + uv_snapshot!(context.filters(), context.python_uninstall().env(EnvVars::UV_PYTHON, "3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the following required arguments were not provided: + ... + + Usage: uv python uninstall --install-dir ... + + For more information, try '--help'. + "###); + + // We should ignore `UV_PYTHON` here and respect `--all` + uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").env(EnvVars::UV_PYTHON, "3.11"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Searching for Python installations + Uninstalled 2 versions in [TIME] + - cpython-3.11.11-[PLATFORM] + - cpython-3.12.9-[PLATFORM] + "###); + + // Uninstall with no targets should error + uv_snapshot!(context.filters(), context.python_uninstall(), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the following required arguments were not provided: + ... + + Usage: uv python uninstall --install-dir ... + + For more information, try '--help'. + "###); + + // Uninstall with conflicting options should error + uv_snapshot!(context.filters(), context.python_uninstall().arg("--all").arg("3.12"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: the argument '--all' cannot be used with '...' + + Usage: uv python uninstall --all --install-dir ... + + For more information, try '--help'. + "###); +} + #[cfg(target_os = "macos")] #[test] -fn python_dylib_install_name_is_patched_on_install() { +fn python_install_patch_dylib() { use assert_cmd::assert::OutputAssertExt; use uv_python::managed::platform_key_from_env; diff --git a/crates/uv/tests/it/run.rs b/crates/uv/tests/it/run.rs index 1a0ac87e05b73..651e9478b4eba 100644 --- a/crates/uv/tests/it/run.rs +++ b/crates/uv/tests/it/run.rs @@ -815,7 +815,7 @@ fn run_pep723_script_lock() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -833,7 +833,7 @@ fn run_pep723_script_lock() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] - "### + "# ); }); @@ -1728,7 +1728,7 @@ fn run_locked() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - existing, @r###" + existing, @r#" version = 1 requires-python = ">=3.12" @@ -1766,6 +1766,7 @@ fn run_locked() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "anyio", specifier = "==3.7.0" }] [[package]] @@ -1776,7 +1777,7 @@ fn run_locked() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] - "###); + "#); } ); @@ -4350,3 +4351,20 @@ fn detect_infinite_recursion() -> Result<()> { Ok(()) } + +#[test] +fn run_uv_variable() { + let context = TestContext::new("3.12"); + + // Display the `UV` variable + uv_snapshot!( + context.filters(), + context.run().arg("python").arg("-c").arg("import os; print(os.environ['UV'])"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + [UV] + + ----- stderr ----- + "###); +} diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index cf05fc61b988f..f72a0f2ba21d6 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -51,7 +51,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { // Resolution should use the lowest direct version, and generate hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -215,14 +215,14 @@ fn resolve_uv_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Resolution should use the highest version, and generate hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .arg("--resolution=highest"), @r#" + .arg("--resolution=highest"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -386,7 +386,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Resolution should use the highest version, and omit hashes. @@ -394,7 +394,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { .arg("--show-settings") .arg("requirements.in") .arg("--resolution=highest") - .arg("--no-generate-hashes"), @r#" + .arg("--no-generate-hashes"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -558,7 +558,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -598,7 +598,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { // Resolution should use the lowest direct version, and generate hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -762,7 +762,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Remove the `uv.toml` file. @@ -771,7 +771,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { // Resolution should use the highest version, and omit hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -905,7 +905,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Add configuration to the `pyproject.toml` file. @@ -923,7 +923,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { // Resolution should use the lowest direct version, and generate hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1087,7 +1087,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -1119,7 +1119,7 @@ fn resolve_index_url() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1312,7 +1312,7 @@ fn resolve_index_url() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Providing an additional index URL on the command-line should be merged with the @@ -1321,7 +1321,7 @@ fn resolve_index_url() -> anyhow::Result<()> { .arg("--show-settings") .arg("requirements.in") .arg("--extra-index-url") - .arg("https://test.pypi.org/simple"), @r#" + .arg("https://test.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1545,7 +1545,7 @@ fn resolve_index_url() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -1577,7 +1577,7 @@ fn resolve_find_links() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1741,7 +1741,7 @@ fn resolve_find_links() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -1772,7 +1772,7 @@ fn resolve_top_level() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -1906,7 +1906,7 @@ fn resolve_top_level() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Write out to both the top-level (`tool.uv`) and the pip section (`tool.uv.pip`). The @@ -1930,7 +1930,7 @@ fn resolve_top_level() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2123,14 +2123,14 @@ fn resolve_top_level() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // But the command-line should take precedence over both. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .arg("--resolution=lowest-direct"), @r#" + .arg("--resolution=lowest-direct"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2323,7 +2323,7 @@ fn resolve_top_level() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -2354,7 +2354,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#" + .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2488,7 +2488,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Add a local configuration to generate hashes. @@ -2502,7 +2502,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#" + .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2636,7 +2636,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Add a local configuration to override the user configuration. @@ -2650,7 +2650,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#" + .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2784,7 +2784,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // However, the user-level `tool.uv.pip` settings override the project-level `tool.uv` settings. @@ -2800,7 +2800,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#" + .env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###" success: true exit_code: 0 ----- stdout ----- @@ -2934,7 +2934,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -3128,7 +3128,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> { // Resolution should use the lowest direct version, and generate hashes. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -3262,7 +3262,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -3304,7 +3304,7 @@ fn resolve_both() -> anyhow::Result<()> { // Resolution should succeed, but warn that the `pip` section in `pyproject.toml` is ignored. uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -3469,7 +3469,7 @@ fn resolve_both() -> anyhow::Result<()> { ----- stderr ----- warning: Found both a `uv.toml` file and a `[tool.uv]` section in an adjacent `pyproject.toml`. The `[tool.uv]` section will be ignored in favor of the `uv.toml` file. - "# + "### ); Ok(()) @@ -3598,7 +3598,7 @@ fn resolve_config_file() -> anyhow::Result<()> { .arg("--show-settings") .arg("--config-file") .arg(config.path()) - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -3762,7 +3762,7 @@ fn resolve_config_file() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Write in `pyproject.toml` schema. @@ -3870,7 +3870,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .current_dir(&child), @r#" + .current_dir(&child), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4004,7 +4004,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Adding a `tool.uv` section should cause us to ignore the `uv.toml`. @@ -4021,7 +4021,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") .arg("requirements.in") - .current_dir(&child), @r#" + .current_dir(&child), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4155,7 +4155,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -4180,7 +4180,7 @@ fn allow_insecure_host() -> anyhow::Result<()> { uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("--show-settings") - .arg("requirements.in"), @r#" + .arg("requirements.in"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4325,7 +4325,7 @@ fn allow_insecure_host() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) @@ -4353,7 +4353,7 @@ fn index_priority() -> anyhow::Result<()> { .arg("requirements.in") .arg("--show-settings") .arg("--index-url") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4548,14 +4548,14 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path()) .arg("requirements.in") .arg("--show-settings") .arg("--default-index") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4750,7 +4750,7 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); let config = context.temp_dir.child("uv.toml"); @@ -4763,7 +4763,7 @@ fn index_priority() -> anyhow::Result<()> { .arg("requirements.in") .arg("--show-settings") .arg("--default-index") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -4958,7 +4958,7 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Prefer the `--index` from the CLI, but treat the index from the file as the default. @@ -4966,7 +4966,7 @@ fn index_priority() -> anyhow::Result<()> { .arg("requirements.in") .arg("--show-settings") .arg("--index") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -5161,7 +5161,7 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); let config = context.temp_dir.child("uv.toml"); @@ -5176,7 +5176,7 @@ fn index_priority() -> anyhow::Result<()> { .arg("requirements.in") .arg("--show-settings") .arg("--index-url") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -5371,7 +5371,7 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); // Prefer the `--extra-index-url` from the CLI, but not as the default. @@ -5379,7 +5379,7 @@ fn index_priority() -> anyhow::Result<()> { .arg("requirements.in") .arg("--show-settings") .arg("--extra-index-url") - .arg("https://cli.pypi.org/simple"), @r#" + .arg("https://cli.pypi.org/simple"), @r###" success: true exit_code: 0 ----- stdout ----- @@ -5574,7 +5574,7 @@ fn index_priority() -> anyhow::Result<()> { } ----- stderr ----- - "# + "### ); Ok(()) diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__black-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__black-lock-file.snap index aa69b9d056a45..747dd888d7f6e 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__black-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__black-lock-file.snap @@ -208,6 +208,7 @@ uvloop = [ ] [package.metadata] +provides-extras = ["colorama", "d", "jupyter", "uvloop"] requires-dist = [ { name = "aiohttp", marker = "implementation_name == 'pypy' and sys_platform == 'win32' and extra == 'd'", specifier = ">=3.7.4,!=3.9.0" }, { name = "aiohttp", marker = "(implementation_name != 'pypy' and extra == 'd') or (sys_platform != 'win32' and extra == 'd')", specifier = ">=3.7.4" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__github-wikidata-bot-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__github-wikidata-bot-lock-file.snap index e3a7f3cfcf1aa..04c78bd8c7c68 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__github-wikidata-bot-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__github-wikidata-bot-lock-file.snap @@ -126,6 +126,7 @@ dev = [ ] [package.metadata] +provides-extras = [] requires-dist = [ { name = "cachecontrol", extras = ["filecache"], specifier = ">=0.14,<0.15" }, { name = "mwparserfromhell", specifier = ">=0.6.4,<0.7" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__home-assistant-core-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__home-assistant-core-lock-file.snap index 804d15848b3a0..684dbcb3b2d0b 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__home-assistant-core-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__home-assistant-core-lock-file.snap @@ -663,6 +663,7 @@ dependencies = [ ] [package.metadata] +provides-extras = [] requires-dist = [ { name = "aiodns", specifier = "==3.2.0" }, { name = "aiohttp", specifier = "==3.9.5" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__packse-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__packse-lock-file.snap index 7921525547675..5260599b3c4bd 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__packse-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__packse-lock-file.snap @@ -340,6 +340,7 @@ dev = [ ] [package.metadata] +provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__saleor-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__saleor-lock-file.snap index e937950a4a345..f15b6e3fca5a6 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__saleor-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__saleor-lock-file.snap @@ -1864,6 +1864,7 @@ dependencies = [ ] [package.metadata] +provides-extras = [] requires-dist = [ { name = "adyen", specifier = ">=4.0.0,<5.0.0" }, { name = "aniso8601", specifier = ">=7.0.0,<8.0.0" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap index 3481204a93881..f7143423f55a3 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__transformers-lock-file.snap @@ -5874,6 +5874,7 @@ dev = [ ] [package.metadata] +provides-extras = ["ja", "sklearn", "tf", "tf-cpu", "torch", "accelerate", "retrieval", "flax", "tokenizers", "ftfy", "onnxruntime", "onnx", "modelcreation", "sagemaker", "deepspeed", "optuna", "ray", "sigopt", "integrations", "serving", "audio", "speech", "torch-speech", "tf-speech", "flax-speech", "vision", "timm", "torch-vision", "codecarbon", "video", "sentencepiece", "deepspeed-testing", "quality", "all", "docs-specific", "docs", "torchhub", "agents"] requires-dist = [ { name = "accelerate", marker = "extra == 'accelerate'", specifier = ">=0.21.0" }, { name = "accelerate", marker = "extra == 'agents'", specifier = ">=0.21.0" }, diff --git a/crates/uv/tests/it/snapshots/it__ecosystem__warehouse-lock-file.snap b/crates/uv/tests/it/snapshots/it__ecosystem__warehouse-lock-file.snap index 250e49b735ba0..eea91143c8686 100644 --- a/crates/uv/tests/it/snapshots/it__ecosystem__warehouse-lock-file.snap +++ b/crates/uv/tests/it/snapshots/it__ecosystem__warehouse-lock-file.snap @@ -3957,6 +3957,7 @@ dev = [ ] [package.metadata] +provides-extras = ["deploy"] requires-dist = [ { name = "alembic", specifier = ">=0.7.0" }, { name = "alembic-postgresql-enum" }, diff --git a/crates/uv/tests/it/snapshots/it__workflow__jax_instability-2.snap b/crates/uv/tests/it/snapshots/it__workflow__jax_instability-2.snap index 54b71172a324d..bf32af4bd5884 100644 --- a/crates/uv/tests/it/snapshots/it__workflow__jax_instability-2.snap +++ b/crates/uv/tests/it/snapshots/it__workflow__jax_instability-2.snap @@ -168,6 +168,7 @@ dependencies = [ ] [package.metadata] +provides-extras = [] requires-dist = [{ name = "jax", specifier = "==0.4.17" }] [[package]] diff --git a/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_existing_package_noop-2.snap b/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_existing_package_noop-2.snap index 1724c2885e91b..07e40724a51fc 100644 --- a/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_existing_package_noop-2.snap +++ b/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_existing_package_noop-2.snap @@ -1,5 +1,5 @@ --- -source: crates/uv/tests/workflow.rs +source: crates/uv/tests/it/workflow.rs expression: lock --- version = 1 @@ -336,6 +336,7 @@ dev = [ ] [package.metadata] +provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, diff --git a/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_one_package-2.snap b/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_one_package-2.snap index 1724c2885e91b..07e40724a51fc 100644 --- a/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_one_package-2.snap +++ b/crates/uv/tests/it/snapshots/it__workflow__packse_add_remove_one_package-2.snap @@ -1,5 +1,5 @@ --- -source: crates/uv/tests/workflow.rs +source: crates/uv/tests/it/workflow.rs expression: lock --- version = 1 @@ -336,6 +336,7 @@ dev = [ ] [package.metadata] +provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, diff --git a/crates/uv/tests/it/snapshots/it__workflow__packse_promote_transitive_to_direct_then_remove-2.snap b/crates/uv/tests/it/snapshots/it__workflow__packse_promote_transitive_to_direct_then_remove-2.snap index 1724c2885e91b..07e40724a51fc 100644 --- a/crates/uv/tests/it/snapshots/it__workflow__packse_promote_transitive_to_direct_then_remove-2.snap +++ b/crates/uv/tests/it/snapshots/it__workflow__packse_promote_transitive_to_direct_then_remove-2.snap @@ -1,5 +1,5 @@ --- -source: crates/uv/tests/workflow.rs +source: crates/uv/tests/it/workflow.rs expression: lock --- version = 1 @@ -336,6 +336,7 @@ dev = [ ] [package.metadata] +provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, diff --git a/crates/uv/tests/it/sync.rs b/crates/uv/tests/it/sync.rs index 447d566efa677..de98e2957c91f 100644 --- a/crates/uv/tests/it/sync.rs +++ b/crates/uv/tests/it/sync.rs @@ -1073,7 +1073,7 @@ fn sync_relative_wheel() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1088,6 +1088,10 @@ fn sync_relative_wheel() -> Result<()> { { filename = "ok-1.0.0-py3-none-any.whl", hash = "sha256:79f0b33e6ce1e09eaa1784c8eee275dfe84d215d9c65c652f07c18e85fdaac5f" }, ] + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "relative-wheel" version = "0.1.0" @@ -1097,8 +1101,9 @@ fn sync_relative_wheel() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "ok", path = "wheels/ok-1.0.0-py3-none-any.whl" }] - "### + "# ); } ); @@ -2406,7 +2411,7 @@ fn sync_group_legacy_non_project_member() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2433,6 +2438,7 @@ fn sync_group_legacy_non_project_member() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig", specifier = ">=1" }] [[package]] @@ -2452,7 +2458,7 @@ fn sync_group_legacy_non_project_member() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -2516,7 +2522,7 @@ fn sync_group_self() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -2564,6 +2570,7 @@ fn sync_group_self() -> Result<()> { ] [package.metadata] + provides-extras = ["test"] requires-dist = [ { name = "idna", marker = "extra == 'test'", specifier = ">=3" }, { name = "iniconfig", specifier = ">=2" }, @@ -2584,7 +2591,7 @@ fn sync_group_self() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); }); @@ -2619,6 +2626,151 @@ fn sync_group_self() -> Result<()> { Ok(()) } +#[test] +fn sync_non_existent_extra() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + [project.optional-dependencies] + types = ["sniffio>1"] + async = ["anyio>3"] + "#, + )?; + + context.lock().assert().success(); + + // Requesting a non-existent extra should fail. + uv_snapshot!(context.filters(), context.sync().arg("--extra").arg("baz"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 4 packages in [TIME] + error: Extra `baz` is not defined in the project's `optional-dependencies` table + "###); + + // Excluding a non-existing extra when requesting all extras should fail. + uv_snapshot!(context.filters(), context.sync().arg("--all-extras").arg("--no-extra").arg("baz"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 4 packages in [TIME] + error: Extra `baz` is not defined in the project's `optional-dependencies` table + "###); + + Ok(()) +} + +#[test] +fn sync_non_existent_extra_no_optional_dependencies() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + "#, + )?; + + context.lock().assert().success(); + + // Requesting a non-existent extra should fail. + uv_snapshot!(context.filters(), context.sync().arg("--extra").arg("baz"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 1 package in [TIME] + error: Extra `baz` is not defined in the project's `optional-dependencies` table + "###); + + // Excluding a non-existing extra when requesting all extras should fail. + uv_snapshot!(context.filters(), context.sync().arg("--all-extras").arg("--no-extra").arg("baz"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 1 package in [TIME] + error: Extra `baz` is not defined in the project's `optional-dependencies` table + "###); + + Ok(()) +} + +/// Ensures that we do not perform validation of extras against a lock file that was generated on a +/// version of uv that predates when `provides-extras` feature was added. +#[test] +fn sync_ignore_extras_check_when_no_provides_extras() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + [project.optional-dependencies] + types = ["sniffio>1"] + "#, + )?; + + // Write a lockfile that does not have `provides-extra`, simulating a version that predates when + // the feature was added. + context.temp_dir.child("uv.lock").write_str(indoc! {r#" + version = 1 + requires-python = ">=3.12" + + [[package]] + name = "project" + version = "0.1.0" + source = { virtual = "." } + + [package.optional-dependencies] + types = [ + { name = "sniffio" }, + ] + + [package.metadata] + requires-dist = [{ name = "sniffio", marker = "extra == 'types'", specifier = ">1" }] + + [[package]] + name = "sniffio" + version = "1.3.1" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } + wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, + ] + "#})?; + + // Requesting a non-existent extra should not fail, as no validation should be performed. + uv_snapshot!(context.filters(), context.sync().arg("--frozen").arg("--extra").arg("baz"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Audited in [TIME] + "###); + + Ok(()) +} + /// Regression test for . /// /// Previously, we would read metadata statically from pyproject.toml and write that to `uv.lock`. In @@ -3001,7 +3153,7 @@ fn convert_to_virtual() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3026,8 +3178,9 @@ fn convert_to_virtual() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -3060,7 +3213,7 @@ fn convert_to_virtual() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3085,8 +3238,9 @@ fn convert_to_virtual() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -3128,7 +3282,7 @@ fn convert_to_package() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3153,8 +3307,9 @@ fn convert_to_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -3192,7 +3347,7 @@ fn convert_to_package() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -3217,8 +3372,9 @@ fn convert_to_package() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "iniconfig" }] - "### + "# ); }); @@ -3547,8 +3703,8 @@ fn sync_active_script_environment() -> Result<()> { .filters() .into_iter() .chain(vec![( - r"environments-v1/script-\w+", - "environments-v1/script-[HASH]", + r"environments-v2/script-[a-z0-9]+", + "environments-v2/script-[HASH]", )]) .collect::>(); @@ -3559,8 +3715,8 @@ fn sync_active_script_environment() -> Result<()> { ----- stdout ----- ----- stderr ----- - warning: `VIRTUAL_ENV=foo` does not match the script environment path `[CACHE_DIR]/environments-v1/script-[HASH]` and will be ignored; use `--active` to target the active environment instead - Creating script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + warning: `VIRTUAL_ENV=foo` does not match the script environment path `[CACHE_DIR]/environments-v2/script-[HASH]` and will be ignored; use `--active` to target the active environment instead + Creating script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 3 packages in [TIME] Prepared 3 packages in [TIME] Installed 3 packages in [TIME] @@ -4609,7 +4765,7 @@ fn sync_dynamic_extra() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -4639,6 +4795,7 @@ fn sync_dynamic_extra() -> Result<()> { ] [package.metadata] + provides-extras = ["dev"] requires-dist = [ { name = "iniconfig" }, { name = "typing-extensions", marker = "extra == 'dev'" }, @@ -4652,7 +4809,7 @@ fn sync_dynamic_extra() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); } ); @@ -5385,7 +5542,7 @@ fn sync_all_extras() -> Result<()> { + typing-extensions==4.10.0 "###); - // Sync all extras. + // Sync all extras excluding an extra that exists in both the parent and child. uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--all-extras").arg("--no-extra").arg("types"), @r###" success: true exit_code: 0 @@ -5397,6 +5554,139 @@ fn sync_all_extras() -> Result<()> { - typing-extensions==4.10.0 "###); + // Sync an extra that doesn't exist. + uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--extra").arg("foo"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 8 packages in [TIME] + error: Extra `foo` is not defined in any project's `optional-dependencies` table + "###); + + // Sync all extras excluding an extra that doesn't exist. + uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--all-extras").arg("--no-extra").arg("foo"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 8 packages in [TIME] + error: Extra `foo` is not defined in any project's `optional-dependencies` table + "###); + + Ok(()) +} + +/// Sync all members in a workspace with dynamic extras. +#[test] +fn sync_all_extras_dynamic() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = ["child"] + + [project.optional-dependencies] + types = ["sniffio>1"] + async = ["anyio>3"] + + [build-system] + requires = ["setuptools>=42"] + build-backend = "setuptools.build_meta" + + [tool.uv.workspace] + members = ["child"] + + [tool.uv.sources] + child = { workspace = true } + "#, + )?; + context + .temp_dir + .child("src") + .child("project") + .child("__init__.py") + .touch()?; + + // Add a workspace member. + let child = context.temp_dir.child("child"); + child.child("pyproject.toml").write_str( + r#" + [project] + name = "child" + version = "0.1.0" + requires-python = ">=3.12" + dynamic = ["optional-dependencies"] + + [tool.setuptools.dynamic.optional-dependencies] + dev = { file = "requirements-dev.txt" } + + [build-system] + requires = ["setuptools>=42"] + build-backend = "setuptools.build_meta" + "#, + )?; + child + .child("src") + .child("child") + .child("__init__.py") + .touch()?; + + child + .child("requirements-dev.txt") + .write_str("typing-extensions==4.10.0")?; + + // Generate a lockfile. + context.lock().assert().success(); + + // Sync an extra that exists in the parent. + uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--extra").arg("types"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 6 packages in [TIME] + Prepared 3 packages in [TIME] + Installed 3 packages in [TIME] + + child==0.1.0 (from file://[TEMP_DIR]/child) + + project==0.1.0 (from file://[TEMP_DIR]/) + + sniffio==1.3.1 + "###); + + // Sync a dynamic extra that exists in the child. + uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--extra").arg("dev"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 6 packages in [TIME] + Prepared 1 package in [TIME] + Uninstalled 1 package in [TIME] + Installed 1 package in [TIME] + - sniffio==1.3.1 + + typing-extensions==4.10.0 + "###); + + // Sync a dynamic extra that doesn't exist in the child. + uv_snapshot!(context.filters(), context.sync().arg("--all-packages").arg("--extra").arg("foo"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + Resolved 6 packages in [TIME] + error: Extra `foo` is not defined in any project's `optional-dependencies` table + "###); + Ok(()) } @@ -5804,7 +6094,7 @@ fn sync_stale_egg_info() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.13" @@ -5821,6 +6111,7 @@ fn sync_stale_egg_info() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "member", git = "https://github.com/astral-sh/uv-stale-egg-info-test.git?subdirectory=member" }, { name = "root", git = "https://github.com/astral-sh/uv-stale-egg-info-test.git" }, @@ -5850,7 +6141,7 @@ fn sync_stale_egg_info() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/92/e1/1c8bb3420105e70bdf357d57dd5567202b4ef8d27f810e98bb962d950834/setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c", size = 821485 }, ] - "### + "# ); } ); @@ -5910,7 +6201,7 @@ fn sync_git_repeated_member_static_metadata() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.13" @@ -5927,6 +6218,7 @@ fn sync_git_repeated_member_static_metadata() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "uv-git-workspace-in-root", git = "https://github.com/astral-sh/workspace-in-root-test.git" }, { name = "workspace-member-in-subdir", git = "https://github.com/astral-sh/workspace-in-root-test.git?subdirectory=workspace-member-in-subdir" }, @@ -5944,7 +6236,7 @@ fn sync_git_repeated_member_static_metadata() -> Result<()> { dependencies = [ { name = "uv-git-workspace-in-root" }, ] - "### + "# ); } ); @@ -6003,7 +6295,7 @@ fn sync_git_repeated_member_dynamic_metadata() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.13" @@ -6028,6 +6320,7 @@ fn sync_git_repeated_member_dynamic_metadata() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dependency", git = "https://github.com/astral-sh/uv-dynamic-metadata-test.git?subdirectory=dependency" }, { name = "package", git = "https://github.com/astral-sh/uv-dynamic-metadata-test.git" }, @@ -6059,7 +6352,7 @@ fn sync_git_repeated_member_dynamic_metadata() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/f9/de/dc04a3ea60b22624b51c703a84bbe0184abcd1d0b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }, ] - "### + "# ); } ); @@ -6120,7 +6413,7 @@ fn sync_git_repeated_member_backwards_path() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.13" @@ -6142,6 +6435,7 @@ fn sync_git_repeated_member_backwards_path() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [ { name = "dependency", git = "https://github.com/astral-sh/uv-backwards-path-test?subdirectory=dependency" }, { name = "package", git = "https://github.com/astral-sh/uv-backwards-path-test?subdirectory=root" }, @@ -6154,7 +6448,7 @@ fn sync_git_repeated_member_backwards_path() -> Result<()> { dependencies = [ { name = "dependency" }, ] - "### + "# ); } ); @@ -6301,7 +6595,7 @@ fn sync_git_path_dependency() -> Result<()> { }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.13" @@ -6317,6 +6611,7 @@ fn sync_git_path_dependency() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "package2", git = "https://github.com/astral-sh/uv-path-dependency-test.git?subdirectory=package2" }] [[package]] @@ -6331,7 +6626,7 @@ fn sync_git_path_dependency() -> Result<()> { dependencies = [ { name = "package1" }, ] - "### + "# ); } ); @@ -6408,7 +6703,7 @@ fn sync_build_tag() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -6434,8 +6729,9 @@ fn sync_build_tag() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "build-tag" }] - "### + "# ); }); @@ -6810,25 +7106,25 @@ fn sync_script() -> Result<()> { .filters() .into_iter() .chain(vec![( - r"environments-v1/script-\w+", - "environments-v1/script-[HASH]", + r"environments-v2/script-\w+", + "environments-v2/script-[HASH]", )]) .collect::>(); - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Creating script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Creating script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 3 packages in [TIME] Prepared 3 packages in [TIME] Installed 3 packages in [TIME] + anyio==4.3.0 + idna==3.6 + sniffio==1.3.1 - "###); + "); // If a lockfile didn't exist already, `uv sync --script` shouldn't create one. assert!(!context.temp_dir.child("uv.lock").exists()); @@ -6847,18 +7143,18 @@ fn sync_script() -> Result<()> { "# })?; - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 4 packages in [TIME] Prepared 1 package in [TIME] Installed 1 package in [TIME] + iniconfig==2.0.0 - "###); + "); // Modify the `requires-python`. script.write_str(indoc! { r#" @@ -6874,13 +7170,13 @@ fn sync_script() -> Result<()> { "# })?; - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Recreating script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Recreating script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 6 packages in [TIME] Prepared 2 packages in [TIME] Installed 6 packages in [TIME] @@ -6890,28 +7186,28 @@ fn sync_script() -> Result<()> { + iniconfig==2.0.0 + sniffio==1.3.1 + typing-extensions==4.10.0 - "###); + "); // `--locked` and `--frozen` should fail with helpful error messages. - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] error: `uv sync --locked` requires a script lockfile; run `uv lock --script script.py` to lock the script - "###); + "); - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--frozen"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--frozen"), @r" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] error: `uv sync --frozen` requires a script lockfile; run `uv lock --script script.py` to lock the script - "###); + "); Ok(()) } @@ -6937,8 +7233,8 @@ fn sync_locked_script() -> Result<()> { .filters() .into_iter() .chain(vec![( - r"environments-v1/script-\w+", - "environments-v1/script-[HASH]", + r"environments-v2/script-\w+", + "environments-v2/script-[HASH]", )]) .collect::>(); @@ -7002,20 +7298,20 @@ fn sync_locked_script() -> Result<()> { ); }); - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Creating script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Creating script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 3 packages in [TIME] Prepared 3 packages in [TIME] Installed 3 packages in [TIME] + anyio==4.3.0 + idna==3.6 + sniffio==1.3.1 - "###); + "); // Modify the script's dependencies. script.write_str(indoc! { r#" @@ -7032,29 +7328,29 @@ fn sync_locked_script() -> Result<()> { })?; // Re-run with `--locked`. - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 4 packages in [TIME] error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`. - "###); + "); - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 4 packages in [TIME] Prepared 1 package in [TIME] Installed 1 package in [TIME] + iniconfig==2.0.0 - "###); + "); let lock = context.read("script.py.lock"); @@ -7133,24 +7429,24 @@ fn sync_locked_script() -> Result<()> { })?; // Re-run with `--locked`. - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py").arg("--locked"), @r" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - Recreating script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Recreating script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 6 packages in [TIME] error: The lockfile at `uv.lock` needs to be updated, but `--locked` was provided. To update the lockfile, run `uv lock`. - "###); + "); - uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r###" + uv_snapshot!(&filters, context.sync().arg("--script").arg("script.py"), @r" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- - Using script environment at: [CACHE_DIR]/environments-v1/script-[HASH] + Using script environment at: [CACHE_DIR]/environments-v2/script-[HASH] Resolved 6 packages in [TIME] Prepared 2 packages in [TIME] Installed 6 packages in [TIME] @@ -7160,7 +7456,7 @@ fn sync_locked_script() -> Result<()> { + iniconfig==2.0.0 + sniffio==1.3.1 + typing-extensions==4.10.0 - "###); + "); Ok(()) } diff --git a/crates/uv/tests/it/tree.rs b/crates/uv/tests/it/tree.rs index 8cdb9961b35cd..b5e06f0ff3373 100644 --- a/crates/uv/tests/it/tree.rs +++ b/crates/uv/tests/it/tree.rs @@ -1246,7 +1246,7 @@ fn script() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.11" @@ -1382,7 +1382,7 @@ fn script() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", size = 121067 }, ] - "### + "# ); }); diff --git a/crates/uv/tests/it/workflow.rs b/crates/uv/tests/it/workflow.rs index 204a2137ee958..96669f9d3437a 100644 --- a/crates/uv/tests/it/workflow.rs +++ b/crates/uv/tests/it/workflow.rs @@ -57,8 +57,8 @@ fn packse_add_remove_one_package() { { name = "pypiserver" }, { name = "watchfiles" }, ] - @@ -334,20 +335,21 @@ - [package.metadata] + @@ -335,20 +336,21 @@ + provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, @@ -79,7 +79,7 @@ fn packse_add_remove_one_package() { { name = "syrupy", specifier = ">=4.6.0" }, ] - @@ -599,20 +601,29 @@ + @@ -600,20 +602,29 @@ { name = "rfc3986" }, { name = "rich" }, { name = "urllib3" }, @@ -145,8 +145,8 @@ fn packse_add_remove_one_package() { { name = "pypiserver" }, { name = "watchfiles" }, ] - @@ -335,21 +334,20 @@ - [package.metadata] + @@ -336,21 +335,20 @@ + provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, @@ -167,7 +167,7 @@ fn packse_add_remove_one_package() { { name = "syrupy", specifier = ">=4.6.0" }, ] - @@ -598,29 +596,20 @@ + @@ -599,29 +597,20 @@ { name = "readme-renderer" }, { name = "requests" }, { name = "requests-toolbelt" }, @@ -299,9 +299,9 @@ fn packse_promote_transitive_to_direct_then_remove() { serve = [ { name = "pypiserver" }, { name = "watchfiles" }, - @@ -333,20 +334,21 @@ - + @@ -334,20 +335,21 @@ [package.metadata] + provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, @@ -357,9 +357,9 @@ fn packse_promote_transitive_to_direct_then_remove() { serve = [ { name = "pypiserver" }, { name = "watchfiles" }, - @@ -334,21 +333,20 @@ - + @@ -335,21 +334,20 @@ [package.metadata] + provides-extras = ["index", "serve"] requires-dist = [ { name = "chevron-blue", specifier = ">=0.2.1" }, { name = "hatchling", specifier = ">=1.20.0" }, @@ -431,7 +431,7 @@ fn jax_instability() -> Result<()> { insta::with_settings!({ filters => context.filters(), }, { - assert_snapshot!(diff, @r###" + assert_snapshot!(diff, @r#" --- old +++ new @@ -8,21 +8,21 @@ @@ -457,7 +457,7 @@ fn jax_instability() -> Result<()> { name = "jax" version = "0.4.17" source = { registry = "https://pypi.org/simple" } - @@ -149,28 +149,41 @@ + @@ -149,29 +149,42 @@ { url = "https://files.pythonhosted.org/packages/f3/31/91a2a3c5eb85d2bfa86d7c98f2df5d77dcdefb3d80ca9f9037ad04393acf/scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c", size = 45816713 }, { url = "https://files.pythonhosted.org/packages/ed/be/49a3f999dc91f1a653847f38c34763dcdeaa8a327f3665bdfe9bf5555109/scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35", size = 38929252 }, { url = "https://files.pythonhosted.org/packages/32/48/f605bad3e610efe05a51b56698578f7a98f900513a4bad2c9f12df845cd6/scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067", size = 31356374 }, @@ -486,6 +486,7 @@ fn jax_instability() -> Result<()> { ] [package.metadata] + provides-extras = [] -requires-dist = [{ name = "jax", specifier = "==0.4.17" }] +requires-dist = [ + { name = "jax", specifier = "==0.4.17" }, @@ -500,7 +501,7 @@ fn jax_instability() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/c2/0a/ba9d0ee9536d3ef73a3448e931776e658b36f128d344e175bc32b092a8bf/zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", size = 8247 }, ] - "###); + "#); }); let diff = context.diff_lock(|context| { @@ -511,10 +512,10 @@ fn jax_instability() -> Result<()> { insta::with_settings!({ filters => context.filters(), }, { - assert_snapshot!(diff, @r###" + assert_snapshot!(diff, @r#" --- old +++ new - @@ -149,41 +149,28 @@ + @@ -149,42 +149,29 @@ { url = "https://files.pythonhosted.org/packages/f3/31/91a2a3c5eb85d2bfa86d7c98f2df5d77dcdefb3d80ca9f9037ad04393acf/scipy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e646d8571804a304e1da01040d21577685ce8e2db08ac58e543eaca063453e1c", size = 45816713 }, { url = "https://files.pythonhosted.org/packages/ed/be/49a3f999dc91f1a653847f38c34763dcdeaa8a327f3665bdfe9bf5555109/scipy-1.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:913d6e7956c3a671de3b05ccb66b11bc293f56bfdef040583a7221d9e22a2e35", size = 38929252 }, { url = "https://files.pythonhosted.org/packages/32/48/f605bad3e610efe05a51b56698578f7a98f900513a4bad2c9f12df845cd6/scipy-1.12.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba1b0c7256ad75401c73e4b3cf09d1f176e9bd4248f0d3112170fb2ec4db067", size = 31356374 }, @@ -543,6 +544,7 @@ fn jax_instability() -> Result<()> { ] [package.metadata] + provides-extras = [] -requires-dist = [ - { name = "jax", specifier = "==0.4.17" }, - { name = "tzdata", specifier = ">=2024.1" }, @@ -557,7 +559,7 @@ fn jax_instability() -> Result<()> { wheels = [ { url = "https://files.pythonhosted.org/packages/c2/0a/ba9d0ee9536d3ef73a3448e931776e658b36f128d344e175bc32b092a8bf/zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", size = 8247 }, ] - "###); + "#); }); // Back to where we started. diff --git a/crates/uv/tests/it/workspace.rs b/crates/uv/tests/it/workspace.rs index 62b9db0bd96de..2e58eb2132dd6 100644 --- a/crates/uv/tests/it/workspace.rs +++ b/crates/uv/tests/it/workspace.rs @@ -1199,7 +1199,7 @@ fn workspace_inherit_sources() -> Result<()> { filters => context.filters(), }, { assert_snapshot!( - lock, @r###" + lock, @r#" version = 1 requires-python = ">=3.12" @@ -1221,6 +1221,7 @@ fn workspace_inherit_sources() -> Result<()> { ] [package.metadata] + provides-extras = [] requires-dist = [{ name = "library", editable = "../library" }] [[package]] @@ -1228,11 +1229,19 @@ fn workspace_inherit_sources() -> Result<()> { version = "0.1.0" source = { editable = "../library" } + [package.metadata] + provides-extras = [] + requires-dist = [] + [[package]] name = "workspace" version = "0.1.0" source = { editable = "." } - "### + + [package.metadata] + provides-extras = [] + requires-dist = [] + "# ); }); diff --git a/docs/concepts/projects/init.md b/docs/concepts/projects/init.md index 567c60c018264..5a91ff16f21fa 100644 --- a/docs/concepts/projects/init.md +++ b/docs/concepts/projects/init.md @@ -22,7 +22,7 @@ Applications are the default target for `uv init`, but can also be specified wit $ uv init example-app ``` -The project includes a `pyproject.toml`, a sample file (`hello.py`), a readme, and a Python version +The project includes a `pyproject.toml`, a sample file (`main.py`), a readme, and a Python version pin file (`.python-version`). ```console @@ -30,7 +30,7 @@ $ tree example-app example-app ├── .python-version ├── README.md -├── hello.py +├── main.py └── pyproject.toml ``` @@ -49,7 +49,7 @@ dependencies = [] The sample file defines a `main` function with some standard boilerplate: -```python title="hello.py" +```python title="main.py" def main(): print("Hello from example-app!") @@ -61,7 +61,7 @@ if __name__ == "__main__": Python files can be executed with `uv run`: ```console -$ uv run hello.py +$ uv run main.py Hello from example-project! ``` diff --git a/docs/configuration/environment.md b/docs/configuration/environment.md index a64fb48e08373..432acb18f4439 100644 --- a/docs/configuration/environment.md +++ b/docs/configuration/environment.md @@ -545,6 +545,18 @@ Path to system-level configuration directory on Windows systems. Use to create the tracing durations file via the `tracing-durations-export` feature. +### `UV` + +The path to the binary that was used to invoke uv. + +This is propagated to all subprocesses spawned by uv. + +If the executable was invoked through a symbolic link, some platforms will return the path +of the symbolic link and other platforms will return the path of the symbolic link’s target. + +See for security +considerations. + ### `VIRTUAL_ENV` Used to detect an activated virtual environment. diff --git a/docs/guides/projects.md b/docs/guides/projects.md index 35fae50ca3187..b49c14115a945 100644 --- a/docs/guides/projects.md +++ b/docs/guides/projects.md @@ -32,14 +32,14 @@ uv will create the following files: . ├── .python-version ├── README.md -├── hello.py +├── main.py └── pyproject.toml ``` -The `hello.py` file contains a simple "Hello world" program. Try it out with `uv run`: +The `main.py` file contains a simple "Hello world" program. Try it out with `uv run`: ```console -$ uv run hello.py +$ uv run main.py Hello from hello-world! ``` @@ -60,7 +60,7 @@ A complete listing would look like: │   └── pyvenv.cfg ├── .python-version ├── README.md -├── hello.py +├── main.py ├── pyproject.toml └── uv.lock ``` diff --git a/docs/reference/cli.md b/docs/reference/cli.md index ffc82994da7ee..7c20da7d92fbb 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -4788,7 +4788,7 @@ uv python install [OPTIONS] [TARGETS]...
TARGETS

The Python version(s) to install.

-

If not provided, the requested Python version(s) will be read from the .python-versions or .python-version files. If neither file is present, uv will check if it has installed any Python versions. If not, it will install the latest stable version of Python.

+

If not provided, the requested Python version(s) will be read from the UV_PYTHON environment variable then .python-versions or .python-version files. If none of the above are present, uv will check if it has installed any Python versions. If not, it will install the latest stable version of Python.

See uv python to view supported request formats.

@@ -5848,12 +5848,14 @@ uv pip compile [OPTIONS] ...

This setting has no effect when used in the uv pip interface.

-
--python python

The Python interpreter to use during resolution.

+
--python, -p python

The Python interpreter to use during resolution.

A Python interpreter is required for building source distributions to determine package metadata when there are not wheels.

The interpreter is also used to determine the default minimum Python version, unless --python-version is provided.

+

This option respects UV_PYTHON, but when set via environment variable, it is overridden by --python-version.

+

See uv python for details on Python discovery and supported request formats.

--python-platform python-platform

The platform for which requirements should be resolved.

@@ -5955,7 +5957,7 @@ uv pip compile [OPTIONS] ...
  • only-system: Only use system Python installations; never use managed Python installations
  • -
    --python-version, -p python-version

    The Python version to use for resolution.

    +
    --python-version python-version

    The Python version to use for resolution.

    For example, 3.8 or 3.8.17.