Skip to content

Conversation

@MeitarR
Copy link
Contributor

@MeitarR MeitarR commented Oct 31, 2025

continuation PR based on #14687

@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch 2 times, most recently from 26d3bb9 to 259bc5f Compare October 31, 2025 22:44
@MeitarR
Copy link
Contributor Author

MeitarR commented Oct 31, 2025

I successfully rebased the old PR on the updated main. Later, I will also try to fix the CR comments from there.

@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch 3 times, most recently from 9273a33 to d4d65a2 Compare November 7, 2025 19:12
@MeitarR MeitarR marked this pull request as ready for review November 7, 2025 19:28
@MeitarR
Copy link
Contributor Author

MeitarR commented Nov 7, 2025

@konstin, I added a WireMock test and fixed the confusing comment. It should be ready for review.

Tell me if the test is what you expected

@Gankra Gankra self-requested a review November 10, 2025 20:16
Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow this is great! I have a few nits but this seems solid.

Comment on lines 913 to 1024
Source::Path(ref path) => fs_err::read(path.as_ref())?.into(),
Source::Http(ref url) => {
let (mut reader, size) = read_url(url, client).await?;
let capacity = size.and_then(|s| s.try_into().ok()).unwrap_or(1_048_576);
let mut buf = Vec::with_capacity(capacity);
reader.read_to_end(&mut buf).await?;
buf.into()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be adding context to these errors..?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would we do that?

I see that read_url already has different error types.

(BTW, I see that there is another usage of read_url later in the file that does the same)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can test this by running with an arbitrary large file (so you can abort before it finished), and turning the network off mid-download:

$ UV_HTTP_TIMEOUT=1 cargo run python install 3.14 --python-downloads-json-url https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl
error: error decoding response body
  Caused by: request or response body error
  Caused by: operation timed out

We should make sure that we show at least the URL in the error message.

For example, this is the error message when network isn't available when starting the download:

$ UV_HTTP_TIMEOUT=1 cargo run python install 3.14 --python-downloads-json-url https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl
error: Failed to download https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl
  Caused by: error sending request for url (https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl)
  Caused by: client error (Connect)
  Caused by: dns error
  Caused by: failed to lookup address information: Name or service not known

We're also not retrying network failures as we do else, because we're using the python download client that has automatic retries deactivated, but don't implement our own retry loop, and don't do any caching. read_url fits badly here, CachedClient has the features we want: Retries, serde integration and caching.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the retrying, can you add a test to network.rs for --python-downloads-json-url?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added context for the errors there


$ UV_HTTP_TIMEOUT=1 cargo run python install 3.14 --python-downloads-json-url https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl
error: Error while fetching remote python downloads json from 'https://files.pythonhosted.org/packages/a9/8c/3da60787bcf70add986c4ad485993026ac0ca74f2fc21410bc4eb1bb7695/torch-2.9.1-cp314-cp314t-manylinux_2_28_x86_64.whl'
  Caused by: error decoding response body
  Caused by: request or response body error
  Caused by: operation timed out

About the other comments, I will address them in a later PR, as this PR is very conflict-prone

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Agreed to have this as a followup)

Source::Path(ref path) => fs_err::read(path.as_ref())?.into(),
Source::Http(ref url) => {
let (mut reader, size) = read_url(url, client).await?;
let capacity = size.and_then(|s| s.try_into().ok()).unwrap_or(1_048_576);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preallocating a 1MB buffer seems a bit aggressive? Is that a pattern copied from somewhere else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From reading the code (which @geofft wrote), I see that the 1MB is only relevant when we can't get the size of the buffer, and the only real case (if I understand correctly) is when in the HTTP response there where no content-length header.

Maybe it is somehow related to #14687 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.bytes(), the non-streaming version, has a better collector for this, but it doesn't really fit with the current read_url

// this by parsing into a Map<String, IgnoredAny> which allows any valid JSON on the
// value side. (Because it's zero-sized, Clippy suggests Set<String>, but that won't
// have the same parsing effect.)
#[allow(clippy::zero_sized_map_values)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting nod to future-compat, sure.

#[allow(clippy::zero_sized_map_values)]
|e| {
let source = match json_source {
Source::BuiltIn => "EMBEDDED IN THE BINARY".to_owned(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch 2 times, most recently from 3ab69a6 to be31b12 Compare November 11, 2025 20:38
Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be mergeable, but this has a non-trivial rebase to do :(

@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch 2 times, most recently from e2c9b66 to 1d5a0a4 Compare November 14, 2025 18:37
geofft and others added 10 commits November 14, 2025 23:13
In preparation for supporting download sources over HTTP, change the
implicit creation of the download list to an explicit async constructor.
Also pass it a BaseClient which will be used in the next commit.
…wnload list

If the JSON does not deserialize, check to see if any key is named
"version" and print a different error message hinting at upgrading uv.

The intention is that we will add this field on backwards-incompatible
changes (and set it to an integer or string or something else that does
not deserialize into a JsonPythonDownload).
Co-authored-by: Aria Desires <aria.desires@gmail.com>
@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch from 1d5a0a4 to c101699 Compare November 14, 2025 21:14
@MeitarR MeitarR force-pushed the remote-python-downloads-json-url branch from 62a645f to 5ec9b6f Compare November 14, 2025 22:15
@Gankra Gankra merged commit b982677 into astral-sh:main Nov 14, 2025
161 checks passed
@MeitarR MeitarR mentioned this pull request Nov 15, 2025
3 tasks
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Nov 18, 2025
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.9.9` -> `0.9.10` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (astral-sh/uv)</summary>

### [`v0.9.10`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0910)

[Compare Source](astral-sh/uv@0.9.9...0.9.10)

Released on 2025-11-17.

##### Enhancements

- Add support for `SSL_CERT_DIR` ([#&#8203;16473](astral-sh/uv#16473))
- Enforce UTF‑8-encoded license files during `uv build` ([#&#8203;16699](astral-sh/uv#16699))
- Error when a `project.license-files` glob matches nothing ([#&#8203;16697](astral-sh/uv#16697))
- `pip install --target` (and `sync`) install Python if necessary ([#&#8203;16694](astral-sh/uv#16694))
- Account for `python_downloads_json_url` in pre-release Python version warnings ([#&#8203;16737](astral-sh/uv#16737))
- Support HTTP/HTTPS URLs in `uv python --python-downloads-json-url` ([#&#8203;16542](astral-sh/uv#16542))

##### Preview features

- Add support for `--upgrade` in `uv python install` ([#&#8203;16676](astral-sh/uv#16676))
- Fix handling of `python install --default` for pre-release Python versions ([#&#8203;16706](astral-sh/uv#16706))
- Add `uv workspace list` to list workspace members ([#&#8203;16691](astral-sh/uv#16691))

##### Bug fixes

- Don't check file URLs for ambiguously parsed credentials ([#&#8203;16759](astral-sh/uv#16759))

##### Documentation

- Add a "storage" reference document ([#&#8203;15954](astral-sh/uv#15954))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNzMuMSIsInVwZGF0ZWRJblZlciI6IjQxLjE3My4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants