Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions crates/uv-python/src/installation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,14 @@ impl PythonInstallation {
) -> Result<Self, Error> {
let request = request.unwrap_or(&PythonRequest::Default);

let client = client_builder.build();
let download_list =
ManagedPythonDownloadList::new(&client, python_downloads_json_url).await?;

// Python downloads are performing their own retries to catch stream errors, disable the
// default retries to avoid the middleware performing uncontrolled retries.
let retry_policy = client_builder.retry_policy();
let client = client_builder.clone().retries(0).build();
let download_list =
ManagedPythonDownloadList::new(&client, python_downloads_json_url).await?;

// Search for the installation
let err = match Self::find(
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/pip/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ pub(crate) async fn pip_compile(
// Find an interpreter to use for building distributions
let environment_preference = EnvironmentPreference::from_system_flag(system, false);
let python_preference = python_preference.with_system_flag(system);
let client = client_builder.clone().retries(0).build();
let client = client_builder.build();
let download_list = ManagedPythonDownloadList::new(
&client,
install_mirrors.python_downloads_json_url.as_deref(),
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/python/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub(crate) async fn find(
)
.await?;

let client = client_builder.clone().retries(0).build();
let client = client_builder.build();
let download_list = ManagedPythonDownloadList::new(&client, python_downloads_json_url).await?;

let python = PythonInstallation::find(
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/commands/python/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub(crate) async fn pin(
for pin in file.versions() {
writeln!(printer.stdout(), "{}", pin.to_canonical_string())?;
if let Some(virtual_project) = &virtual_project {
let client = client_builder.clone().retries(0).build();
let client = client_builder.build();
let download_list = ManagedPythonDownloadList::new(
&client,
install_mirrors.python_downloads_json_url.as_deref(),
Expand Down
56 changes: 56 additions & 0 deletions crates/uv/tests/it/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,59 @@ async fn rfc9457_problem_details_license_violation() {
╰─▶ HTTP status client error (403 Forbidden) for url ([SERVER]/packages/tqdm-4.67.1-py3-none-any.whl)
");
}

/// Check the python list error message when the server returns HTTP status 500, a retryable error.
#[tokio::test]
async fn python_list_remote_python_downloads_json_url_http_500() {
let context = TestContext::new("3.12");

let (_server_drop_guard, mock_server_uri) = http_error_server().await;

let python_downloads_json_url = format!("{mock_server_uri}/python_downloads.json");
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
uv_snapshot!(filters, context
.python_list()
.arg("--python-downloads-json-url")
.arg(&python_downloads_json_url)
.env_remove(EnvVars::UV_HTTP_RETRIES)
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @r"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: Error while fetching remote python downloads json from '[SERVER]/python_downloads.json'
Caused by: Request failed after 3 retries
Caused by: Failed to download [SERVER]/python_downloads.json
Caused by: HTTP status server error (500 Internal Server Error) for url ([SERVER]/python_downloads.json)
");
}

/// Check the python list error message when the server returns a retryable IO error.
#[tokio::test]
async fn python_list_remote_python_downloads_json_url_io_error() {
let context = TestContext::new("3.12");

let (_server_drop_guard, mock_server_uri) = io_error_server().await;

let python_downloads_json_url = format!("{mock_server_uri}/python_downloads.json");
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
uv_snapshot!(filters, context
.python_list()
.arg("--python-downloads-json-url")
.arg(&python_downloads_json_url)
.env_remove(EnvVars::UV_HTTP_RETRIES)
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @r"
success: false
exit_code: 2
----- stdout -----

----- stderr -----
error: Error while fetching remote python downloads json from '[SERVER]/python_downloads.json'
Caused by: Failed to download [SERVER]/python_downloads.json
Caused by: Request failed after 3 retries
Caused by: error sending request for url ([SERVER]/python_downloads.json)
Caused by: client error (SendRequest)
Caused by: connection closed before message completed
");
}
Loading