Move parsing http retries to EnvironmentOptions (#16284)

## Summary
- Move  parsing `UV_HTTP_RETRIES` to `EnvironmentOptions`

Relates https://github.com/astral-sh/uv/issues/14720

## Test Plan

- Tests with existing tests
This commit is contained in:
Andrei Berenda 2025-10-21 13:14:37 +04:00 committed by GitHub
parent 29cec24d5c
commit 51e8da2d1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 123 additions and 91 deletions

2
Cargo.lock generated
View file

@ -5291,7 +5291,6 @@ dependencies = [
"predicates",
"regex",
"reqwest",
"reqwest-retry",
"rkyv",
"rustc-hash",
"self-replace",
@ -6605,6 +6604,7 @@ dependencies = [
"tracing",
"url",
"uv-cache-info",
"uv-client",
"uv-configuration",
"uv-dirs",
"uv-distribution-types",

View file

@ -44,7 +44,6 @@ use crate::middleware::OfflineMiddleware;
use crate::tls::read_identity;
use crate::{Connectivity, WrappedReqwestError};
/// Do not use this value directly outside tests, use [`retries_from_env`] instead.
pub const DEFAULT_RETRIES: u32 = 3;
/// Maximum number of redirects to follow before giving up.
@ -154,11 +153,13 @@ impl BaseClientBuilder<'_> {
allow_insecure_host: Vec<TrustedHost>,
preview: Preview,
timeout: Duration,
retries: u32,
) -> Self {
Self {
preview,
allow_insecure_host,
native_tls,
retries,
connectivity,
timeout,
..Self::default()
@ -202,15 +203,6 @@ impl<'a> BaseClientBuilder<'a> {
self
}
/// Read the retry count from [`EnvVars::UV_HTTP_RETRIES`] if set, otherwise use the default
/// retries.
///
/// Errors when [`EnvVars::UV_HTTP_RETRIES`] is not a valid u32.
pub fn retries_from_env(mut self) -> Result<Self, RetryParsingError> {
self.retries = retries_from_env()?;
Ok(self)
}
#[must_use]
pub fn native_tls(mut self, native_tls: bool) -> Self {
self.native_tls = native_tls;
@ -292,7 +284,7 @@ impl<'a> BaseClientBuilder<'a> {
}
/// Create a [`RetryPolicy`] for the client.
fn retry_policy(&self) -> ExponentialBackoff {
pub fn retry_policy(&self) -> ExponentialBackoff {
let mut builder = ExponentialBackoff::builder();
if env::var_os(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY).is_some() {
builder = builder.retry_bounds(Duration::from_millis(0), Duration::from_millis(0));
@ -1093,19 +1085,6 @@ pub enum RetryParsingError {
ParseInt(#[from] ParseIntError),
}
/// Read the retry count from [`EnvVars::UV_HTTP_RETRIES`] if set, otherwise, make no change.
///
/// Errors when [`EnvVars::UV_HTTP_RETRIES`] is not a valid u32.
pub fn retries_from_env() -> Result<u32, RetryParsingError> {
// TODO(zanieb): We should probably parse this in another layer, but there's not a natural
// fit for it right now
if let Some(value) = env::var_os(EnvVars::UV_HTTP_RETRIES) {
Ok(value.to_string_lossy().as_ref().parse::<u32>()?)
} else {
Ok(DEFAULT_RETRIES)
}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -1,7 +1,7 @@
pub use base_client::{
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware,
RedirectClientWithMiddleware, RequestBuilder, RetryParsingError, UvRetryableStrategy,
is_transient_network_error, retries_from_env,
is_transient_network_error,
};
pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
pub use error::{Error, ErrorKind, WrappedReqwestError};

View file

@ -27,7 +27,7 @@ use uv_auth::{Credentials, PyxTokenStore};
use uv_cache::{Cache, Refresh};
use uv_client::{
BaseClient, MetadataFormat, OwnedArchive, RegistryClientBuilder, RequestBuilder,
RetryParsingError, UvRetryableStrategy, retries_from_env,
RetryParsingError, UvRetryableStrategy,
};
use uv_configuration::{KeyringProviderType, TrustedPublishing};
use uv_distribution_filename::{DistFilename, SourceDistExtension, SourceDistFilename};
@ -382,6 +382,7 @@ pub async fn upload(
filename: &DistFilename,
registry: &DisplaySafeUrl,
client: &BaseClient,
retry_policy: ExponentialBackoff,
credentials: &Credentials,
check_url_client: Option<&CheckUrlClient<'_>>,
download_concurrency: &Semaphore,
@ -389,8 +390,6 @@ pub async fn upload(
) -> Result<bool, PublishError> {
let mut n_past_retries = 0;
let start_time = SystemTime::now();
// N.B. We cannot use the client policy here because it is set to zero retries.
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(retries_from_env()?);
loop {
let (request, idx) = build_upload_request(
file,

View file

@ -5,11 +5,10 @@ use std::str::FromStr;
use indexmap::IndexMap;
use ref_cast::RefCast;
use reqwest_retry::policies::ExponentialBackoff;
use tracing::{debug, info};
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, retries_from_env};
use uv_client::BaseClientBuilder;
use uv_pep440::{Prerelease, Version};
use uv_platform::{Arch, Libc, Os, Platform};
use uv_preview::Preview;
@ -231,8 +230,7 @@ impl PythonInstallation {
// Python downloads are performing their own retries to catch stream errors, disable the
// default retries to avoid the middleware from performing uncontrolled retries.
let retry_policy =
ExponentialBackoff::builder().build_with_max_retries(retries_from_env()?);
let retry_policy = client_builder.retry_policy();
let client = client_builder.clone().retries(0).build();
info!("Fetching requested Python...");

View file

@ -17,6 +17,7 @@ workspace = true
[dependencies]
uv-cache-info = { workspace = true, features = ["schemars"] }
uv-client = { workspace = true }
uv-configuration = { workspace = true, features = ["schemars", "clap"] }
uv-dirs = { workspace = true }
uv-distribution-types = { workspace = true, features = ["schemars"] }

View file

@ -585,6 +585,7 @@ pub struct EnvironmentOptions {
pub install_mirrors: PythonInstallMirrors,
pub log_context: Option<bool>,
pub http_timeout: Duration,
pub http_retries: u32,
pub upload_http_timeout: Duration,
pub concurrency: Concurrency,
#[cfg(feature = "tracing-durations-export")]
@ -596,9 +597,11 @@ impl EnvironmentOptions {
pub fn new() -> Result<Self, Error> {
// Timeout options, matching https://doc.rust-lang.org/nightly/cargo/reference/config.html#httptimeout
// `UV_REQUEST_TIMEOUT` is provided for backwards compatibility with v0.1.6
let http_timeout = parse_u64_environment_variable(EnvVars::UV_HTTP_TIMEOUT)?
.or(parse_u64_environment_variable(EnvVars::UV_REQUEST_TIMEOUT)?)
.or(parse_u64_environment_variable(EnvVars::HTTP_TIMEOUT)?)
let http_timeout = parse_integer_environment_variable(EnvVars::UV_HTTP_TIMEOUT)?
.or(parse_integer_environment_variable(
EnvVars::UV_REQUEST_TIMEOUT,
)?)
.or(parse_integer_environment_variable(EnvVars::HTTP_TIMEOUT)?)
.map(Duration::from_secs);
Ok(Self {
@ -610,13 +613,9 @@ impl EnvironmentOptions {
EnvVars::UV_PYTHON_INSTALL_REGISTRY,
)?,
concurrency: Concurrency {
downloads: parse_non_zero_usize_environment_variable(
EnvVars::UV_CONCURRENT_DOWNLOADS,
)?,
builds: parse_non_zero_usize_environment_variable(EnvVars::UV_CONCURRENT_BUILDS)?,
installs: parse_non_zero_usize_environment_variable(
EnvVars::UV_CONCURRENT_INSTALLS,
)?,
downloads: parse_integer_environment_variable(EnvVars::UV_CONCURRENT_DOWNLOADS)?,
builds: parse_integer_environment_variable(EnvVars::UV_CONCURRENT_BUILDS)?,
installs: parse_integer_environment_variable(EnvVars::UV_CONCURRENT_INSTALLS)?,
},
install_mirrors: PythonInstallMirrors {
python_install_mirror: parse_string_environment_variable(
@ -630,11 +629,15 @@ impl EnvironmentOptions {
)?,
},
log_context: parse_boolish_environment_variable(EnvVars::UV_LOG_CONTEXT)?,
upload_http_timeout: parse_u64_environment_variable(EnvVars::UV_UPLOAD_HTTP_TIMEOUT)?
upload_http_timeout: parse_integer_environment_variable(
EnvVars::UV_UPLOAD_HTTP_TIMEOUT,
)?
.map(Duration::from_secs)
.or(http_timeout)
.unwrap_or(Duration::from_secs(15 * 60)),
http_timeout: http_timeout.unwrap_or(Duration::from_secs(30)),
http_retries: parse_integer_environment_variable(EnvVars::UV_HTTP_RETRIES)?
.unwrap_or(uv_client::DEFAULT_RETRIES),
#[cfg(feature = "tracing-durations-export")]
tracing_durations_file: parse_path_environment_variable(
EnvVars::TRACING_DURATIONS_FILE,
@ -716,10 +719,7 @@ fn parse_string_environment_variable(name: &'static str) -> Result<Option<String
}
}
fn parse_integer_environment_variable<T>(
name: &'static str,
err_msg: &'static str,
) -> Result<Option<T>, Error>
fn parse_integer_environment_variable<T>(name: &'static str) -> Result<Option<T>, Error>
where
T: std::str::FromStr + Copy,
<T as std::str::FromStr>::Err: std::fmt::Display,
@ -732,7 +732,7 @@ where
std::env::VarError::NotUnicode(err) => Err(Error::InvalidEnvironmentVariable {
name: name.to_string(),
value: err.to_string_lossy().to_string(),
err: err_msg.to_string(),
err: "expected a valid UTF-8 string".to_string(),
}),
};
}
@ -743,26 +743,14 @@ where
match value.parse::<T>() {
Ok(v) => Ok(Some(v)),
Err(_) => Err(Error::InvalidEnvironmentVariable {
Err(err) => Err(Error::InvalidEnvironmentVariable {
name: name.to_string(),
value,
err: err_msg.to_string(),
err: err.to_string(),
}),
}
}
/// Parse a integer environment variable.
fn parse_u64_environment_variable(name: &'static str) -> Result<Option<u64>, Error> {
parse_integer_environment_variable(name, "expected an integer")
}
/// Parse a non-zero usize environment variable.
fn parse_non_zero_usize_environment_variable(
name: &'static str,
) -> Result<Option<NonZeroUsize>, Error> {
parse_integer_environment_variable(name, "expected a non-zero positive integer")
}
#[cfg(feature = "tracing-durations-export")]
/// Parse a path environment variable.
fn parse_path_environment_variable(name: &'static str) -> Option<PathBuf> {

View file

@ -91,7 +91,6 @@ owo-colors = { workspace = true }
petgraph = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true }
reqwest-retry = { workspace = true }
rkyv = { workspace = true }
rustc-hash = { workspace = true }
serde = { workspace = true }

View file

@ -44,6 +44,7 @@ pub(crate) async fn login(
network_settings.allow_insecure_host.clone(),
preview,
network_settings.timeout,
network_settings.retries,
)
.auth_integration(AuthIntegration::NoAuthMiddleware)
.build();

View file

@ -104,6 +104,7 @@ async fn pyx_logout(
network_settings.allow_insecure_host.clone(),
preview,
network_settings.timeout,
network_settings.retries,
)
.build();

View file

@ -33,6 +33,7 @@ pub(crate) async fn token(
network_settings.allow_insecure_host.clone(),
preview,
network_settings.timeout,
network_settings.retries,
)
.auth_integration(AuthIntegration::NoAuthMiddleware)
.build();

View file

@ -2,12 +2,11 @@ use std::path::Path;
use std::str::FromStr;
use anyhow::{Context, Result};
use reqwest_retry::policies::ExponentialBackoff;
use tokio::process::Command;
use uv_bin_install::{Binary, bin_install};
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, retries_from_env};
use uv_client::BaseClientBuilder;
use uv_pep440::Version;
use uv_preview::{Preview, PreviewFeatures};
use uv_warnings::warn_user;
@ -64,9 +63,9 @@ pub(crate) async fn format(
// Parse version if provided
let version = version.as_deref().map(Version::from_str).transpose()?;
let retry_policy = client_builder.retry_policy();
// Python downloads are performing their own retries to catch stream errors, disable the
// default retries to avoid the middleware from performing uncontrolled retries.
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(retries_from_env()?);
let client = client_builder.retries(0).build();
// Get the path to Ruff, downloading it if necessary

View file

@ -129,6 +129,7 @@ pub(crate) async fn publish(
.auth_integration(AuthIntegration::NoAuthMiddleware)
.wrap_existing(&upload_client);
let retry_policy = client_builder.retry_policy();
// We're only checking a single URL and one at a time, so 1 permit is sufficient
let download_concurrency = Arc::new(Semaphore::new(1));
@ -222,6 +223,7 @@ pub(crate) async fn publish(
&filename,
&publish_url,
&upload_client,
retry_policy,
&credentials,
check_url_client.as_ref(),
&download_concurrency,

View file

@ -11,11 +11,10 @@ use futures::stream::FuturesUnordered;
use indexmap::IndexSet;
use itertools::{Either, Itertools};
use owo_colors::{AnsiColors, OwoColorize};
use reqwest_retry::policies::ExponentialBackoff;
use rustc_hash::{FxHashMap, FxHashSet};
use tracing::{debug, trace};
use uv_client::{BaseClientBuilder, retries_from_env};
use uv_client::BaseClientBuilder;
use uv_fs::Simplified;
use uv_platform::{Arch, Libc};
use uv_preview::{Preview, PreviewFeatures};
@ -398,9 +397,9 @@ pub(crate) async fn install(
.unique_by(|download| download.key())
.collect::<Vec<_>>();
let retry_policy = client_builder.retry_policy();
// Python downloads are performing their own retries to catch stream errors, disable the
// default retries to avoid the middleware from performing uncontrolled retries.
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(retries_from_env()?);
let client = client_builder.retries(0).build();
let reporter = PythonDownloadReporter::new(printer, downloads.len() as u64);

View file

@ -183,9 +183,9 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
settings.network_settings.native_tls,
settings.network_settings.allow_insecure_host,
settings.preview,
environment.http_timeout,
)
.retries_from_env()?;
settings.network_settings.timeout,
settings.network_settings.retries,
);
Some(
RunCommand::from_args(command, client_builder, *module, *script, *gui_script)
.await?,
@ -456,9 +456,9 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
globals.network_settings.native_tls,
globals.network_settings.allow_insecure_host.clone(),
globals.preview,
environment.http_timeout,
)
.retries_from_env()?;
globals.network_settings.timeout,
globals.network_settings.retries,
);
match *cli.command {
Commands::Auth(AuthNamespace {

View file

@ -184,6 +184,7 @@ pub(crate) struct NetworkSettings {
pub(crate) native_tls: bool,
pub(crate) allow_insecure_host: Vec<TrustedHost>,
pub(crate) timeout: Duration,
pub(crate) retries: u32,
}
impl NetworkSettings {
@ -200,7 +201,6 @@ impl NetworkSettings {
} else {
Connectivity::Online
};
let timeout = environment.http_timeout;
let native_tls = flag(args.native_tls, args.no_native_tls, "native-tls")
.combine(workspace.and_then(|workspace| workspace.globals.native_tls))
.unwrap_or(false);
@ -225,7 +225,8 @@ impl NetworkSettings {
connectivity,
native_tls,
allow_insecure_host,
timeout,
timeout: environment.http_timeout,
retries: environment.http_retries,
}
}
}

View file

@ -323,8 +323,21 @@ async fn install_http_retries() {
----- stdout -----
----- stderr -----
error: Failed to parse `UV_HTTP_RETRIES`
Caused by: invalid digit found in string
error: Failed to parse environment variable `UV_HTTP_RETRIES` with invalid value `foo`: invalid digit found in string
"
);
uv_snapshot!(context.filters(), context.pip_install()
.arg("anyio")
.arg("--index")
.arg(server.uri())
.env(EnvVars::UV_HTTP_RETRIES, "-1"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to parse environment variable `UV_HTTP_RETRIES` with invalid value `-1`: invalid digit found in string
"
);
@ -338,8 +351,7 @@ async fn install_http_retries() {
----- stdout -----
----- stderr -----
error: Failed to parse `UV_HTTP_RETRIES`
Caused by: number too large to fit in target type
error: Failed to parse environment variable `UV_HTTP_RETRIES` with invalid value `999999999999`: number too large to fit in target type
"
);

View file

@ -67,6 +67,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -267,6 +268,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -468,6 +470,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -701,6 +704,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -903,6 +907,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -1081,6 +1086,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -1308,6 +1314,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -1543,6 +1550,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -1836,6 +1844,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -2060,6 +2069,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -2243,6 +2253,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -2476,6 +2487,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -2732,6 +2744,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -2905,6 +2918,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -3078,6 +3092,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -3253,6 +3268,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -3447,6 +3463,7 @@ fn resolve_tool() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -3633,6 +3650,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -3840,6 +3858,7 @@ fn resolve_both() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -4086,6 +4105,7 @@ fn resolve_both_special_fields() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -4411,6 +4431,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -4711,6 +4732,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -4887,6 +4909,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -5082,6 +5105,7 @@ fn allow_insecure_host() -> anyhow::Result<()> {
},
],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -5269,6 +5293,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -5504,6 +5529,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -5745,6 +5771,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -5981,6 +6008,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -6224,6 +6252,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -6460,6 +6489,7 @@ fn index_priority() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -6709,6 +6739,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -6875,6 +6906,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7039,6 +7071,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7205,6 +7238,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7369,6 +7403,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7534,6 +7569,7 @@ fn verify_hashes() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7714,6 +7750,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7827,6 +7864,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -7940,6 +7978,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8053,6 +8092,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8166,6 +8206,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8281,6 +8322,7 @@ fn preview_features() {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8415,6 +8457,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8589,6 +8632,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8786,6 +8830,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -8958,6 +9003,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9124,6 +9170,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9291,6 +9338,7 @@ fn upgrade_pip_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9523,6 +9571,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9641,6 +9690,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9782,6 +9832,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -9898,6 +9949,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -10004,6 +10056,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -10111,6 +10164,7 @@ fn upgrade_project_cli_config_interaction() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -10282,6 +10336,7 @@ fn build_isolation_override() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,
@ -10451,6 +10506,7 @@ fn build_isolation_override() -> anyhow::Result<()> {
native_tls: false,
allow_insecure_host: [],
timeout: [TIME],
retries: 3,
},
concurrency: Concurrency {
downloads: 50,

View file

@ -885,8 +885,6 @@ fn seed_older_python_version() {
#[test]
fn create_venv_with_invalid_http_timeout() {
let context = TestContext::new_with_versions(&["3.12"]).with_http_timeout("not_a_number");
// Create a virtual environment at `.venv`.
uv_snapshot!(context.filters(), context.venv()
.arg(context.venv.as_os_str())
.arg("--python")
@ -896,15 +894,13 @@ fn create_venv_with_invalid_http_timeout() {
----- stdout -----
----- stderr -----
error: Failed to parse environment variable `UV_HTTP_TIMEOUT` with invalid value `not_a_number`: expected an integer
error: Failed to parse environment variable `UV_HTTP_TIMEOUT` with invalid value `not_a_number`: invalid digit found in string
"###);
}
#[test]
fn create_venv_with_invalid_concurrent_installs() {
let context = TestContext::new_with_versions(&["3.12"]).with_concurrent_installs("0");
// Create a virtual environment at `.venv`.
uv_snapshot!(context.filters(), context.venv()
.arg(context.venv.as_os_str())
.arg("--python")
@ -914,7 +910,7 @@ fn create_venv_with_invalid_concurrent_installs() {
----- stdout -----
----- stderr -----
error: Failed to parse environment variable `UV_CONCURRENT_INSTALLS` with invalid value `0`: expected a non-zero positive integer
error: Failed to parse environment variable `UV_CONCURRENT_INSTALLS` with invalid value `0`: number would be zero for non-zero type
"###);
}