mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Compare commits
16 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ddb1577a93 | ||
![]() |
d31e6ad7c7 | ||
![]() |
3a77b9cdd9 | ||
![]() |
1d027bd92a | ||
![]() |
bb738aeb44 | ||
![]() |
fc758bb755 | ||
![]() |
1308c85efe | ||
![]() |
f609e1ddaf | ||
![]() |
eaf517efd8 | ||
![]() |
e8bc3950ef | ||
![]() |
06af93fce7 | ||
![]() |
8afbd86f03 | ||
![]() |
a1cda6213c | ||
![]() |
39cdfe9981 | ||
![]() |
85c0fc963b | ||
![]() |
c3f13d2505 |
32 changed files with 299 additions and 207 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -1585,7 +1585,7 @@ jobs:
|
|||
run: chmod +x ./uv
|
||||
|
||||
- name: "Configure AWS credentials"
|
||||
uses: aws-actions/configure-aws-credentials@3d8cba388a057b13744d61818a337e40a119b1a7
|
||||
uses: aws-actions/configure-aws-credentials@f503a1870408dcf2c35d5c2b8a68e69211042c7d
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
|
|
|
@ -12,7 +12,7 @@ repos:
|
|||
- id: validate-pyproject
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.33.1
|
||||
rev: v1.34.0
|
||||
hooks:
|
||||
- id: typos
|
||||
|
||||
|
@ -42,7 +42,7 @@ repos:
|
|||
types_or: [yaml, json5]
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.12.1
|
||||
rev: v0.12.2
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
- id: ruff
|
||||
|
|
115
Cargo.lock
generated
115
Cargo.lock
generated
|
@ -189,9 +189,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.3.1"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
|
||||
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener-strategy",
|
||||
|
@ -1165,9 +1165,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
|
||||
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"pin-project-lite",
|
||||
|
@ -1698,7 +1698,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
"webpki-roots 0.26.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1707,6 +1707,7 @@ version = "0.1.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -1714,7 +1715,9 @@ dependencies = [
|
|||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
|
@ -1945,6 +1948,16 @@ version = "2.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||
|
||||
[[package]]
|
||||
name = "iri-string"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.15"
|
||||
|
@ -3062,9 +3075,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.15"
|
||||
version = "0.12.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
|
||||
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"base64 0.22.1",
|
||||
|
@ -3079,18 +3092,14 @@ dependencies = [
|
|||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -3098,17 +3107,16 @@ dependencies = [
|
|||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-socks",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"windows-registry 0.4.0",
|
||||
"webpki-roots 1.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3351,15 +3359,6 @@ dependencies = [
|
|||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.11.0"
|
||||
|
@ -3428,9 +3427,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d"
|
||||
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"ref-cast",
|
||||
|
@ -3442,9 +3441,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b13ed22d6d49fe23712e068770b5c4df4a693a2b02eeff8e7ca3135627a24f6"
|
||||
checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3968,9 +3967,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "test-log"
|
||||
version = "0.2.17"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f"
|
||||
checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b"
|
||||
dependencies = [
|
||||
"test-log-macros",
|
||||
"tracing-subscriber",
|
||||
|
@ -3978,9 +3977,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "test-log-macros"
|
||||
version = "0.2.17"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f"
|
||||
checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -4172,18 +4171,6 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-socks"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"futures-util",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.17"
|
||||
|
@ -4266,6 +4253,24 @@ dependencies = [
|
|||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.3"
|
||||
|
@ -5635,7 +5640,7 @@ dependencies = [
|
|||
"uv-trampoline-builder",
|
||||
"uv-warnings",
|
||||
"which",
|
||||
"windows-registry 0.5.3",
|
||||
"windows-registry",
|
||||
"windows-result 0.3.4",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
@ -5839,7 +5844,7 @@ dependencies = [
|
|||
"tracing",
|
||||
"uv-fs",
|
||||
"uv-static",
|
||||
"windows-registry 0.5.3",
|
||||
"windows-registry",
|
||||
"windows-result 0.3.4",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
@ -6221,6 +6226,15 @@ dependencies = [
|
|||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.8"
|
||||
|
@ -6448,17 +6462,6 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
dependencies = [
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.5.3"
|
||||
|
|
|
@ -142,7 +142,7 @@ ref-cast = { version = "1.0.24" }
|
|||
reflink-copy = { version = "0.1.19" }
|
||||
regex = { version = "1.10.6" }
|
||||
regex-automata = { version = "0.4.8", default-features = false, features = ["dfa-build", "dfa-search", "perf", "std", "syntax"] }
|
||||
reqwest = { version = "=0.12.15", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
|
||||
reqwest = { version = "0.12.22", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
|
||||
reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8", features = ["multipart"] }
|
||||
reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" }
|
||||
rkyv = { version = "0.8.8", features = ["bytecheck"] }
|
||||
|
|
|
@ -982,6 +982,45 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_redirect_preserves_fragment() -> Result<()> {
|
||||
for status in &[301, 302, 303, 307, 308] {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("GET"))
|
||||
.respond_with(
|
||||
ResponseTemplate::new(*status)
|
||||
.insert_header("location", format!("{}/redirect", server.uri())),
|
||||
)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let request = Client::new()
|
||||
.get(format!("{}#fragment", server.uri()))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let response = Client::builder()
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.build()
|
||||
.unwrap()
|
||||
.execute(request.try_clone().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let redirect_request =
|
||||
request_into_redirect(request, &response, CrossOriginCredentialsPolicy::Secure)?
|
||||
.unwrap();
|
||||
assert!(
|
||||
redirect_request
|
||||
.url()
|
||||
.fragment()
|
||||
.is_some_and(|fragment| fragment == "fragment")
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_redirect_removes_authorization_header_on_cross_origin() -> Result<()> {
|
||||
for status in &[301, 302, 303, 307, 308] {
|
||||
|
|
|
@ -1416,44 +1416,6 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_redirect_preserve_fragment() -> Result<(), Error> {
|
||||
let redirect_server = MockServer::start().await;
|
||||
|
||||
// Configure the redirect server to respond with a 307 with a relative URL.
|
||||
Mock::given(method("GET"))
|
||||
.respond_with(ResponseTemplate::new(307).insert_header("Location", "/foo".to_string()))
|
||||
.mount(&redirect_server)
|
||||
.await;
|
||||
|
||||
Mock::given(method("GET"))
|
||||
.and(path_regex("/foo"))
|
||||
.respond_with(ResponseTemplate::new(200))
|
||||
.mount(&redirect_server)
|
||||
.await;
|
||||
|
||||
let cache = Cache::temp()?;
|
||||
let registry_client = RegistryClientBuilder::new(cache).build();
|
||||
let client = registry_client.cached_client().uncached();
|
||||
|
||||
let mut url = DisplaySafeUrl::parse(&redirect_server.uri())?;
|
||||
url.set_fragment(Some("fragment"));
|
||||
|
||||
assert_eq!(
|
||||
client
|
||||
.for_host(&url)
|
||||
.get(Url::from(url.clone()))
|
||||
.send()
|
||||
.await?
|
||||
.url()
|
||||
.to_string(),
|
||||
format!("{}/foo#fragment", redirect_server.uri()),
|
||||
"Requests should preserve fragment"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_failing_files() {
|
||||
// 1.7.7 has an invalid requires-python field (double comma), 1.7.8 is valid
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::{borrow::Cow, str::FromStr};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
|
||||
use uv_pep508::PackageName;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::str::FromStr;
|
||||
use std::{borrow::Cow, fmt::Formatter};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::{fmt::Formatter, str::FromStr};
|
||||
|
||||
use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError};
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use serde::{Deserialize, Deserializer};
|
||||
use std::{borrow::Cow, str::FromStr};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
/// A host specification (wildcard, or host, with optional scheme and/or port) for which
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
//! flags set.
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::{borrow::Cow, path::Path};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{Index, IndexUrl};
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::{borrow::Cow, ops::Deref};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
|
||||
use http::StatusCode;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
|
|
@ -2,11 +2,11 @@ use std::{ffi::OsString, path::PathBuf};
|
|||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
#[error("Failed to read from zip file")]
|
||||
Zip(#[from] zip::result::ZipError),
|
||||
#[error(transparent)]
|
||||
#[error("Failed to read from zip file")]
|
||||
AsyncZip(#[from] async_zip::error::ZipError),
|
||||
#[error(transparent)]
|
||||
#[error("I/O operation failed during extraction")]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error(
|
||||
"The top-level of the archive must only contain a list directory, but it contains: {0:?}"
|
||||
|
|
|
@ -18,11 +18,16 @@ use uv_redacted::DisplaySafeUrl;
|
|||
use crate::Pep508Url;
|
||||
|
||||
/// A wrapper around [`Url`] that preserves the original string.
|
||||
///
|
||||
/// The original string is not preserved after serialization/deserialization.
|
||||
#[derive(Debug, Clone, Eq)]
|
||||
pub struct VerbatimUrl {
|
||||
/// The parsed URL.
|
||||
url: DisplaySafeUrl,
|
||||
/// The URL as it was provided by the user.
|
||||
///
|
||||
/// Even if originally set, this will be [`None`] after
|
||||
/// serialization/deserialization.
|
||||
given: Option<ArcStr>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::fmt::Formatter;
|
|||
use std::sync::Arc;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use pubgrub::{
|
||||
DefaultStringReporter, DerivationTree, Derived, External, Range, Ranges, Reporter, Term,
|
||||
|
@ -156,7 +157,7 @@ impl<T> From<tokio::sync::mpsc::error::SendError<T>> for ResolveError {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>;
|
||||
pub type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>;
|
||||
|
||||
/// A wrapper around [`pubgrub::error::NoSolutionError`] that displays a resolution failure report.
|
||||
pub struct NoSolutionError {
|
||||
|
@ -367,6 +368,11 @@ impl NoSolutionError {
|
|||
NoSolutionHeader::new(self.env.clone())
|
||||
}
|
||||
|
||||
/// Get the conflict derivation tree for external analysis
|
||||
pub fn derivation_tree(&self) -> &ErrorTree {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Hint at limiting the resolver environment if universal resolution failed for a target
|
||||
/// that is not the current platform or not the current Python version.
|
||||
fn hint_disjoint_targets(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
|
@ -404,6 +410,15 @@ impl NoSolutionError {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the packages that are involved in this error.
|
||||
pub fn packages(&self) -> impl Iterator<Item = &PackageName> {
|
||||
self.error
|
||||
.packages()
|
||||
.into_iter()
|
||||
.filter_map(|p| p.name())
|
||||
.unique()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for NoSolutionError {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use std::{borrow::Cow, str::FromStr};
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
|
||||
use jiff::{Timestamp, ToSpan, tz::TimeZone};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub use dependency_mode::DependencyMode;
|
||||
pub use error::{NoSolutionError, NoSolutionHeader, ResolveError, SentinelRange};
|
||||
pub use error::{ErrorTree, NoSolutionError, NoSolutionHeader, ResolveError, SentinelRange};
|
||||
pub use exclude_newer::ExcludeNewer;
|
||||
pub use exclusions::Exclusions;
|
||||
pub use flat_index::{FlatDistributions, FlatIndex};
|
||||
|
@ -54,7 +54,7 @@ mod options;
|
|||
mod pins;
|
||||
mod preferences;
|
||||
mod prerelease;
|
||||
mod pubgrub;
|
||||
pub mod pubgrub;
|
||||
mod python_requirement;
|
||||
mod redirect;
|
||||
mod resolution;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
pub(crate) use crate::pubgrub::dependencies::PubGrubDependency;
|
||||
pub(crate) use crate::pubgrub::distribution::PubGrubDistribution;
|
||||
pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
|
||||
pub use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
|
||||
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority, PubGrubTiebreaker};
|
||||
pub(crate) use crate::pubgrub::report::PubGrubReportFormatter;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::python_requirement::PythonRequirement;
|
|||
|
||||
/// [`Arc`] wrapper around [`PubGrubPackageInner`] to make cloning (inside PubGrub) cheap.
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub(crate) struct PubGrubPackage(Arc<PubGrubPackageInner>);
|
||||
pub struct PubGrubPackage(Arc<PubGrubPackageInner>);
|
||||
|
||||
impl Deref for PubGrubPackage {
|
||||
type Target = PubGrubPackageInner;
|
||||
|
@ -39,7 +39,7 @@ impl From<PubGrubPackageInner> for PubGrubPackage {
|
|||
/// package (e.g., `black[colorama]`), and mark it as a dependency of the real package (e.g.,
|
||||
/// `black`). We then discard the virtual packages at the end of the resolution process.
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub(crate) enum PubGrubPackageInner {
|
||||
pub enum PubGrubPackageInner {
|
||||
/// The root package, which is used to start the resolution process.
|
||||
Root(Option<PackageName>),
|
||||
/// A Python version.
|
||||
|
@ -295,7 +295,7 @@ impl PubGrubPackage {
|
|||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash, Ord)]
|
||||
pub(crate) enum PubGrubPython {
|
||||
pub enum PubGrubPython {
|
||||
/// The Python version installed in the current environment.
|
||||
Installed,
|
||||
/// The Python version for which dependencies are being resolved.
|
||||
|
|
|
@ -7,7 +7,7 @@ use uv_platform_tags::{AbiTag, Tags};
|
|||
|
||||
/// The reason why a package or a version cannot be used.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum UnavailableReason {
|
||||
pub enum UnavailableReason {
|
||||
/// The entire package cannot be used.
|
||||
Package(UnavailablePackage),
|
||||
/// A single version cannot be used.
|
||||
|
@ -29,7 +29,7 @@ impl Display for UnavailableReason {
|
|||
/// Most variant are from [`MetadataResponse`] without the error source, since we don't format
|
||||
/// the source and we want to merge unavailable messages across versions.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum UnavailableVersion {
|
||||
pub enum UnavailableVersion {
|
||||
/// Version is incompatible because it has no usable distributions
|
||||
IncompatibleDist(IncompatibleDist),
|
||||
/// The wheel metadata was found, but could not be parsed.
|
||||
|
@ -123,7 +123,7 @@ impl From<&MetadataUnavailable> for UnavailableVersion {
|
|||
|
||||
/// The package is unavailable and cannot be used.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum UnavailablePackage {
|
||||
pub enum UnavailablePackage {
|
||||
/// Index lookups were disabled (i.e., `--no-index`) and the package was not found in a flat index (i.e. from `--find-links`).
|
||||
NoIndex,
|
||||
/// Network requests were disabled (i.e., `--offline`), and the package was not found in the cache.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//!
|
||||
//! Then lowers them into a dependency specification.
|
||||
|
||||
#[cfg(feature = "schemars")]
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Formatter;
|
||||
|
|
|
@ -385,7 +385,7 @@ async fn lock_and_sync(
|
|||
let default_groups = default_dependency_groups(project.pyproject_toml())?;
|
||||
let default_extras = DefaultExtras::default();
|
||||
let groups = DependencyGroups::default().with_defaults(default_groups);
|
||||
let extras = ExtrasSpecification::from_all_extras().with_defaults(default_extras);
|
||||
let extras = ExtrasSpecification::default().with_defaults(default_extras);
|
||||
let install_options = InstallOptions::default();
|
||||
|
||||
// Convert to an `AddTarget` by attaching the appropriate interpreter or environment.
|
||||
|
|
|
@ -15,7 +15,7 @@ fn build_basic() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -133,7 +133,7 @@ fn build_sdist() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -189,7 +189,7 @@ fn build_wheel() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -245,7 +245,7 @@ fn build_sdist_wheel() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -303,7 +303,7 @@ fn build_wheel_from_sdist() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -412,7 +412,7 @@ fn build_fail() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -488,7 +488,6 @@ fn build_workspace() -> Result<()> {
|
|||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"\\\.", ""),
|
||||
(r"\[project\]", "[PKG]"),
|
||||
(r"\[member\]", "[PKG]"),
|
||||
|
@ -694,7 +693,6 @@ fn build_all_with_failure() -> Result<()> {
|
|||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"\\\.", ""),
|
||||
(r"\[project\]", "[PKG]"),
|
||||
(r"\[member-\w+\]", "[PKG]"),
|
||||
|
@ -840,7 +838,7 @@ fn build_constraints() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -901,7 +899,7 @@ fn build_sha() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -1187,7 +1185,7 @@ fn build_tool_uv_sources() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let build = context.temp_dir.child("backend");
|
||||
|
@ -1337,7 +1335,6 @@ fn build_non_package() -> Result<()> {
|
|||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"\\\.", ""),
|
||||
(r"\[project\]", "[PKG]"),
|
||||
(r"\[member\]", "[PKG]"),
|
||||
|
@ -1930,7 +1927,7 @@ fn build_with_nonnormalized_name() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
|
||||
.chain([(r"\\\.", "")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let project = context.temp_dir.child("project");
|
||||
|
@ -1981,3 +1978,60 @@ fn build_with_nonnormalized_name() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that `--force-pep517` is respected.
|
||||
///
|
||||
/// The error messages for a broken project are different for direct builds vs. PEP 517.
|
||||
#[test]
|
||||
fn force_pep517() -> Result<()> {
|
||||
// We need to use a real `uv_build` package.
|
||||
let context = TestContext::new("3.12").with_exclude_newer("2025-05-27T00:00:00Z");
|
||||
|
||||
context
|
||||
.init()
|
||||
.arg("--build-backend")
|
||||
.arg("uv")
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "1.0.0"
|
||||
|
||||
[tool.uv.build-backend]
|
||||
module-name = "does_not_exist"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv_build>=0.5.15,<10000"]
|
||||
build-backend = "uv_build"
|
||||
"#})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.build().env("RUST_BACKTRACE", "0"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Building source distribution (uv build backend)...
|
||||
× Failed to build `[TEMP_DIR]/`
|
||||
╰─▶ Expected a Python module at: `src/does_not_exist/__init__.py`
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.build().arg("--force-pep517").env("RUST_BACKTRACE", "0"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Building source distribution...
|
||||
Error: Missing module directory for `does_not_exist` in `src`. Found: `temp`
|
||||
× Failed to build `[TEMP_DIR]/`
|
||||
├─▶ The build backend returned an error
|
||||
╰─▶ Call to `uv_build.build_sdist` failed (exit status: 1)
|
||||
hint: This usually indicates a problem with the package or the build environment.
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -517,6 +517,8 @@ impl TestContext {
|
|||
if cfg!(windows) {
|
||||
filters.push((" --link-mode <LINK_MODE>".to_string(), String::new()));
|
||||
filters.push((r#"link-mode = "copy"\n"#.to_string(), String::new()));
|
||||
// Unix uses "exit status", Windows uses "exit code"
|
||||
filters.push((r"exit code: ".to_string(), "exit status: ".to_string()));
|
||||
}
|
||||
|
||||
filters.extend(
|
||||
|
|
|
@ -7246,10 +7246,7 @@ fn fail_to_add_revert_project() -> Result<()> {
|
|||
.child("setup.py")
|
||||
.write_str("1/0")?;
|
||||
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.add().arg("./child"), @r#"
|
||||
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -7351,10 +7348,7 @@ fn fail_to_edit_revert_project() -> Result<()> {
|
|||
.child("setup.py")
|
||||
.write_str("1/0")?;
|
||||
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.add().arg("./child"), @r#"
|
||||
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
|
|
@ -23617,10 +23617,7 @@ fn lock_derivation_chain_prod() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.lock(), @r###"
|
||||
|
@ -23677,10 +23674,7 @@ fn lock_derivation_chain_extra() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.lock(), @r###"
|
||||
|
@ -23739,10 +23733,7 @@ fn lock_derivation_chain_group() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.lock(), @r###"
|
||||
|
@ -23812,10 +23803,7 @@ fn lock_derivation_chain_extended() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.lock(), @r###"
|
||||
|
|
|
@ -14679,10 +14679,7 @@ fn compile_derivation_chain() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.pip_compile().arg("pyproject.toml"), @r###"
|
||||
|
|
|
@ -342,10 +342,7 @@ dependencies = ["flask==1.0.x"]
|
|||
let requirements_txt = context.temp_dir.child("requirements.txt");
|
||||
requirements_txt.write_str("./path_dep")?;
|
||||
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.pip_install()
|
||||
uv_snapshot!(context.filters(), context.pip_install()
|
||||
.arg("-r")
|
||||
.arg("requirements.txt"), @r###"
|
||||
success: false
|
||||
|
@ -4930,10 +4927,7 @@ fn no_build_isolation() -> Result<()> {
|
|||
requirements_in.write_str("anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz")?;
|
||||
|
||||
// We expect the build to fail, because `setuptools` is not installed.
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.pip_install()
|
||||
uv_snapshot!(context.filters(), context.pip_install()
|
||||
.arg("-r")
|
||||
.arg("requirements.in")
|
||||
.arg("--no-build-isolation"), @r###"
|
||||
|
@ -5001,10 +4995,7 @@ fn respect_no_build_isolation_env_var() -> Result<()> {
|
|||
requirements_in.write_str("anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz")?;
|
||||
|
||||
// We expect the build to fail, because `setuptools` is not installed.
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.pip_install()
|
||||
uv_snapshot!(context.filters(), context.pip_install()
|
||||
.arg("-r")
|
||||
.arg("requirements.in")
|
||||
.env(EnvVars::UV_NO_BUILD_ISOLATION, "yes"), @r###"
|
||||
|
@ -8601,10 +8592,7 @@ fn install_build_isolation_package() -> Result<()> {
|
|||
)?;
|
||||
|
||||
// Running `uv pip install` should fail for iniconfig.
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.pip_install()
|
||||
uv_snapshot!(context.filters(), context.pip_install()
|
||||
.arg("--no-build-isolation-package")
|
||||
.arg("iniconfig")
|
||||
.arg(package.path()), @r###"
|
||||
|
@ -8931,10 +8919,7 @@ fn missing_top_level() {
|
|||
fn sklearn() {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.pip_install().arg("sklearn"), @r###"
|
||||
uv_snapshot!(context.filters(), context.pip_install().arg("sklearn"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -8984,10 +8969,7 @@ fn resolve_derivation_chain() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.pip_install()
|
||||
|
|
|
@ -1122,10 +1122,7 @@ fn sync_build_isolation_package() -> Result<()> {
|
|||
)?;
|
||||
|
||||
// Running `uv sync` should fail for iniconfig.
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(filters, context.sync().arg("--no-build-isolation-package").arg("source-distribution"), @r###"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--no-build-isolation-package").arg("source-distribution"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -1215,10 +1212,7 @@ fn sync_build_isolation_extra() -> Result<()> {
|
|||
)?;
|
||||
|
||||
// Running `uv sync` should fail for the `compile` extra.
|
||||
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
|
||||
.chain(context.filters())
|
||||
.collect::<Vec<_>>();
|
||||
uv_snapshot!(&filters, context.sync().arg("--extra").arg("compile"), @r###"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--extra").arg("compile"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -1239,7 +1233,7 @@ fn sync_build_isolation_extra() -> Result<()> {
|
|||
"###);
|
||||
|
||||
// Running `uv sync` with `--all-extras` should also fail.
|
||||
uv_snapshot!(&filters, context.sync().arg("--all-extras"), @r###"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--all-extras"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -6985,10 +6979,7 @@ fn sync_derivation_chain() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.sync(), @r###"
|
||||
|
@ -7051,10 +7042,7 @@ fn sync_derivation_chain_extra() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.sync().arg("--extra").arg("wsgi"), @r###"
|
||||
|
@ -7119,10 +7107,7 @@ fn sync_derivation_chain_group() -> Result<()> {
|
|||
let filters = context
|
||||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"/.*/src", "/[TMP]/src"),
|
||||
])
|
||||
.chain([(r"/.*/src", "/[TMP]/src")])
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
uv_snapshot!(filters, context.sync().arg("--group").arg("wsgi"), @r###"
|
||||
|
|
|
@ -1682,7 +1682,6 @@ fn tool_install_uninstallable() {
|
|||
.filters()
|
||||
.into_iter()
|
||||
.chain([
|
||||
(r"exit code: 1", "exit status: 1"),
|
||||
(r"bdist\.[^/\\\s]+(-[^/\\\s]+)?", "bdist.linux-x86_64"),
|
||||
(r"\\\.", ""),
|
||||
(r"#+", "#"),
|
||||
|
|
|
@ -1958,3 +1958,57 @@ fn version_set_evil_constraints() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bump the version with conflicting extras, to ensure we're activating the correct subset of
|
||||
/// extras during the resolve.
|
||||
#[test]
|
||||
fn version_extras() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "myproject"
|
||||
version = "1.10.31"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[project.optional-dependencies]
|
||||
foo = ["requests"]
|
||||
bar = ["httpx"]
|
||||
baz = ["flask"]
|
||||
|
||||
[tool.uv]
|
||||
conflicts = [[{"extra" = "foo"}, {"extra" = "bar"}]]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.version()
|
||||
.arg("--bump").arg("patch"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
myproject 1.10.31 => 1.10.32
|
||||
|
||||
----- stderr -----
|
||||
Resolved 19 packages in [TIME]
|
||||
Audited in [TIME]
|
||||
");
|
||||
|
||||
// Sync an extra, we should not remove it.
|
||||
context.sync().arg("--extra").arg("foo").assert().success();
|
||||
|
||||
uv_snapshot!(context.filters(), context.version()
|
||||
.arg("--bump").arg("patch"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
myproject 1.10.32 => 1.10.33
|
||||
|
||||
----- stderr -----
|
||||
Resolved 19 packages in [TIME]
|
||||
Audited in [TIME]
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -324,7 +324,7 @@ so multiple files are not needed to lock development dependencies.
|
|||
The uv lockfile is always [universal](../../concepts/resolution.md#universal-resolution), so
|
||||
multiple files are not needed to
|
||||
[lock dependencies for each platform](#platform-specific-dependencies). This ensures that all
|
||||
developers
|
||||
developers are using consistent, locked versions of dependencies regardless of their machine.
|
||||
|
||||
The uv lockfile also supports concepts like
|
||||
[pinning packages to specific indexes](../../concepts/indexes.md#pinning-a-package-to-an-index),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue