Add UV_HTTP_RETRIES to customize retry counts (#14544)

I want to increase this number in CI and was surprised we didn't support
configuration yet.
This commit is contained in:
Zanie Blue 2025-07-11 07:35:27 -05:00 committed by GitHub
parent 2e0f399eeb
commit 71470b7b1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 143 additions and 1 deletions

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::{env, io, iter}; use std::{env, io, iter};
use anyhow::Context;
use anyhow::anyhow; use anyhow::anyhow;
use http::{ use http::{
HeaderMap, HeaderName, HeaderValue, Method, StatusCode, HeaderMap, HeaderName, HeaderValue, Method, StatusCode,
@ -166,6 +167,25 @@ impl<'a> BaseClientBuilder<'a> {
self self
} }
/// 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(self) -> anyhow::Result<Self> {
// 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(self.retries(
value
.to_string_lossy()
.as_ref()
.parse::<u32>()
.context("Failed to parse `UV_HTTP_RETRIES`")?,
))
} else {
Ok(self)
}
}
#[must_use] #[must_use]
pub fn native_tls(mut self, native_tls: bool) -> Self { pub fn native_tls(mut self, native_tls: bool) -> Self {
self.native_tls = native_tls; self.native_tls = native_tls;
@ -238,7 +258,11 @@ impl<'a> BaseClientBuilder<'a> {
/// Create a [`RetryPolicy`] for the client. /// Create a [`RetryPolicy`] for the client.
fn retry_policy(&self) -> ExponentialBackoff { fn retry_policy(&self) -> ExponentialBackoff {
ExponentialBackoff::builder().build_with_max_retries(self.retries) 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));
}
builder.build_with_max_retries(self.retries)
} }
pub fn build(&self) -> BaseClient { pub fn build(&self) -> BaseClient {

View file

@ -115,6 +115,11 @@ impl<'a> RegistryClientBuilder<'a> {
self self
} }
pub fn retries_from_env(mut self) -> anyhow::Result<Self> {
self.base_client_builder = self.base_client_builder.retries_from_env()?;
Ok(self)
}
#[must_use] #[must_use]
pub fn native_tls(mut self, native_tls: bool) -> Self { pub fn native_tls(mut self, native_tls: bool) -> Self {
self.base_client_builder = self.base_client_builder.native_tls(native_tls); self.base_client_builder = self.base_client_builder.native_tls(native_tls);

View file

@ -31,6 +31,9 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
WheelFilename(#[from] uv_distribution_filename::WheelFilenameError), WheelFilename(#[from] uv_distribution_filename::WheelFilenameError),
#[error("Failed to construct HTTP client")]
ClientError(#[source] anyhow::Error),
#[error(transparent)] #[error(transparent)]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
} }

View file

@ -402,6 +402,9 @@ impl EnvVars {
/// Timeout (in seconds) for HTTP requests. (default: 30 s) /// Timeout (in seconds) for HTTP requests. (default: 30 s)
pub const UV_HTTP_TIMEOUT: &'static str = "UV_HTTP_TIMEOUT"; pub const UV_HTTP_TIMEOUT: &'static str = "UV_HTTP_TIMEOUT";
/// The number of retries for HTTP requests. (default: 3)
pub const UV_HTTP_RETRIES: &'static str = "UV_HTTP_RETRIES";
/// Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`. /// Timeout (in seconds) for HTTP requests. Equivalent to `UV_HTTP_TIMEOUT`.
pub const UV_REQUEST_TIMEOUT: &'static str = "UV_REQUEST_TIMEOUT"; pub const UV_REQUEST_TIMEOUT: &'static str = "UV_REQUEST_TIMEOUT";
@ -659,6 +662,9 @@ impl EnvVars {
#[attr_hidden] #[attr_hidden]
pub const UV_TEST_VENDOR_LINKS_URL: &'static str = "UV_TEST_VENDOR_LINKS_URL"; pub const UV_TEST_VENDOR_LINKS_URL: &'static str = "UV_TEST_VENDOR_LINKS_URL";
/// Used to disable delay for HTTP retries in tests.
pub const UV_TEST_NO_HTTP_RETRY_DELAY: &'static str = "UV_TEST_NO_HTTP_RETRY_DELAY";
/// Used to set an index url for tests. /// Used to set an index url for tests.
#[attr_hidden] #[attr_hidden]
pub const UV_TEST_INDEX_URL: &'static str = "UV_TEST_INDEX_URL"; pub const UV_TEST_INDEX_URL: &'static str = "UV_TEST_INDEX_URL";

View file

@ -207,6 +207,7 @@ async fn build_impl(
} = settings; } = settings;
let client_builder = BaseClientBuilder::default() let client_builder = BaseClientBuilder::default()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -179,6 +179,7 @@ pub(crate) async fn pip_compile(
} }
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -99,6 +99,7 @@ pub(crate) async fn pip_install(
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -87,6 +87,7 @@ pub(crate) async fn pip_list(
let capabilities = IndexCapabilities::default(); let capabilities = IndexCapabilities::default();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -81,6 +81,7 @@ pub(crate) async fn pip_sync(
preview: PreviewMode, preview: PreviewMode,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -86,6 +86,7 @@ pub(crate) async fn pip_tree(
let capabilities = IndexCapabilities::default(); let capabilities = IndexCapabilities::default();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -42,6 +42,7 @@ pub(crate) async fn pip_uninstall(
let start = std::time::Instant::now(); let start = std::time::Instant::now();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -176,6 +176,7 @@ pub(crate) async fn add(
} }
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -329,6 +330,7 @@ pub(crate) async fn add(
.ok(); .ok();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(settings.resolver.keyring_provider) .keyring(settings.resolver.keyring_provider)

View file

@ -218,6 +218,7 @@ async fn init_script(
warn_user_once!("`--package` is a no-op for Python scripts, which are standalone"); warn_user_once!("`--package` is a no-op for Python scripts, which are standalone");
} }
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -348,6 +349,7 @@ async fn init_project(
let reporter = PythonDownloadReporter::single(printer); let reporter = PythonDownloadReporter::single(printer);
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -99,6 +99,7 @@ pub(crate) async fn lock(
let script = match script { let script = match script {
Some(ScriptPath::Path(path)) => { Some(ScriptPath::Path(path)) => {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -588,6 +589,7 @@ async fn do_lock(
// Initialize the client. // Initialize the client.
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(*keyring_provider) .keyring(*keyring_provider)

View file

@ -690,6 +690,7 @@ impl ScriptInterpreter {
} }
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -946,6 +947,7 @@ impl ProjectInterpreter {
} }
let client_builder = BaseClientBuilder::default() let client_builder = BaseClientBuilder::default()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -1656,6 +1658,8 @@ pub(crate) async fn resolve_names(
} = settings; } = settings;
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()
.map_err(uv_requirements::Error::ClientError)?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(*keyring_provider) .keyring(*keyring_provider)
@ -1813,6 +1817,7 @@ pub(crate) async fn resolve_environment(
} = spec.requirements; } = spec.requirements;
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(*keyring_provider) .keyring(*keyring_provider)
@ -1984,6 +1989,7 @@ pub(crate) async fn sync_environment(
} = settings; } = settings;
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)
@ -2147,6 +2153,7 @@ pub(crate) async fn update_environment(
} = settings; } = settings;
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(*keyring_provider) .keyring(*keyring_provider)

View file

@ -618,6 +618,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
// If we're isolating the environment, use an ephemeral virtual environment as the // If we're isolating the environment, use an ephemeral virtual environment as the
// base environment for the project. // base environment for the project.
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -859,6 +860,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
let interpreter = { let interpreter = {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -929,6 +931,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
None None
} else { } else {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -1526,6 +1529,7 @@ impl RunCommand {
.tempfile()?; .tempfile()?;
let client = BaseClientBuilder::new() let client = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()) .allow_insecure_host(network_settings.allow_insecure_host.clone())

View file

@ -623,6 +623,7 @@ pub(super) async fn do_sync(
} = settings; } = settings;
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.keyring(keyring_provider) .keyring(keyring_provider)

View file

@ -215,6 +215,7 @@ pub(crate) async fn tree(
let client = RegistryClientBuilder::new( let client = RegistryClientBuilder::new(
cache.clone().with_refresh(Refresh::All(Timestamp::now())), cache.clone().with_refresh(Refresh::All(Timestamp::now())),
) )
.retries_from_env()?
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.allow_insecure_host(network_settings.allow_insecure_host.clone()) .allow_insecure_host(network_settings.allow_insecure_host.clone())

View file

@ -95,6 +95,7 @@ pub(crate) async fn publish(
false, false,
); );
let registry_client_builder = RegistryClientBuilder::new(cache.clone()) let registry_client_builder = RegistryClientBuilder::new(cache.clone())
.retries_from_env()?
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.allow_insecure_host(network_settings.allow_insecure_host.clone()) .allow_insecure_host(network_settings.allow_insecure_host.clone())

View file

@ -376,6 +376,7 @@ pub(crate) async fn install(
// Download and unpack the Python versions concurrently // Download and unpack the Python versions concurrently
let client = uv_client::BaseClientBuilder::new() let client = uv_client::BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()) .allow_insecure_host(network_settings.allow_insecure_host.clone())

View file

@ -107,6 +107,7 @@ pub(crate) async fn pin(
} }
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -66,6 +66,7 @@ pub(crate) async fn install(
preview: PreviewMode, preview: PreviewMode,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());
@ -97,6 +98,7 @@ pub(crate) async fn install(
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -690,6 +690,7 @@ async fn get_or_create_environment(
preview: PreviewMode, preview: PreviewMode,
) -> Result<(ToolRequirement, PythonEnvironment), ProjectError> { ) -> Result<(ToolRequirement, PythonEnvironment), ProjectError> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -80,6 +80,7 @@ pub(crate) async fn upgrade(
let reporter = PythonDownloadReporter::single(printer); let reporter = PythonDownloadReporter::single(printer);
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()?
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)
.allow_insecure_host(network_settings.allow_insecure_host.clone()); .allow_insecure_host(network_settings.allow_insecure_host.clone());

View file

@ -193,6 +193,9 @@ async fn venv_impl(
.unwrap_or(PathBuf::from(".venv")), .unwrap_or(PathBuf::from(".venv")),
); );
// TODO(zanieb): We don't use [`BaseClientBuilder::retries_from_env`] here because it's a pain
// to map into a miette diagnostic. We should just remove miette diagnostics here, we're not
// using them elsewhere.
let client_builder = BaseClientBuilder::default() let client_builder = BaseClientBuilder::default()
.connectivity(network_settings.connectivity) .connectivity(network_settings.connectivity)
.native_tls(network_settings.native_tls) .native_tls(network_settings.native_tls)

View file

@ -499,6 +499,66 @@ fn install_package() {
context.assert_command("import flask").success(); context.assert_command("import flask").success();
} }
#[tokio::test]
async fn install_http_retries() {
let context = TestContext::new("3.12");
let server = MockServer::start().await;
// Create a server that always fails, so we can see the number of retries used
Mock::given(method("GET"))
.respond_with(ResponseTemplate::new(503))
.mount(&server)
.await;
uv_snapshot!(context.filters(), context.pip_install()
.arg("anyio")
.arg("--index")
.arg(server.uri())
.env(EnvVars::UV_HTTP_RETRIES, "foo"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to parse `UV_HTTP_RETRIES`
Caused by: invalid digit found in string
"
);
uv_snapshot!(context.filters(), context.pip_install()
.arg("anyio")
.arg("--index")
.arg(server.uri())
.env(EnvVars::UV_HTTP_RETRIES, "999999999999"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Failed to parse `UV_HTTP_RETRIES`
Caused by: number too large to fit in target type
"
);
uv_snapshot!(context.filters(), context.pip_install()
.arg("anyio")
.arg("--index")
.arg(server.uri())
.env(EnvVars::UV_HTTP_RETRIES, "5")
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Request failed after 5 retries
Caused by: Failed to fetch: `http://[LOCALHOST]/anyio/`
Caused by: HTTP status server error (503 Service Unavailable) for url (http://[LOCALHOST]/anyio/)
"
);
}
/// Install a package from a `requirements.txt` into a virtual environment. /// Install a package from a `requirements.txt` into a virtual environment.
#[test] #[test]
fn install_requirements_txt() -> Result<()> { fn install_requirements_txt() -> Result<()> {

View file

@ -102,6 +102,10 @@ Equivalent to the `--token` argument for self update. A GitHub token for authent
Enables fetching files stored in Git LFS when installing a package from a Git repository. Enables fetching files stored in Git LFS when installing a package from a Git repository.
### `UV_HTTP_RETRIES`
The number of retries for HTTP requests. (default: 3)
### `UV_HTTP_TIMEOUT` ### `UV_HTTP_TIMEOUT`
Timeout (in seconds) for HTTP requests. (default: 30 s) Timeout (in seconds) for HTTP requests. (default: 30 s)
@ -416,6 +420,10 @@ WARNING: `UV_SYSTEM_PYTHON=true` is intended for use in continuous integration (
or containerized environments and should be used with caution, as modifying the system or containerized environments and should be used with caution, as modifying the system
Python can lead to unexpected behavior. Python can lead to unexpected behavior.
### `UV_TEST_NO_HTTP_RETRY_DELAY`
Used to disable delay for HTTP retries in tests.
### `UV_TOOL_BIN_DIR` ### `UV_TOOL_BIN_DIR`
Specifies the "bin" directory for installing tool executables. Specifies the "bin" directory for installing tool executables.