-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Support http/https URLs in uv python --python-downloads-json-url
#16542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support http/https URLs in uv python --python-downloads-json-url
#16542
Conversation
26d3bb9 to
259bc5f
Compare
|
I successfully rebased the old PR on the updated main. Later, I will also try to fix the CR comments from there. |
9273a33 to
d4d65a2
Compare
|
@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
left a comment
There was a problem hiding this 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.
crates/uv-python/src/downloads.rs
Outdated
| 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() | ||
| } |
There was a problem hiding this comment.
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..?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably fine.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
crates/uv-python/src/downloads.rs
Outdated
| 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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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)] |
There was a problem hiding this comment.
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(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol
3ab69a6 to
be31b12
Compare
Gankra
left a comment
There was a problem hiding this 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 :(
e2c9b66 to
1d5a0a4
Compare
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>
1d5a0a4 to
c101699
Compare
62a645f to
5ec9b6f
Compare
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` ([#​16473](astral-sh/uv#16473)) - Enforce UTF‑8-encoded license files during `uv build` ([#​16699](astral-sh/uv#16699)) - Error when a `project.license-files` glob matches nothing ([#​16697](astral-sh/uv#16697)) - `pip install --target` (and `sync`) install Python if necessary ([#​16694](astral-sh/uv#16694)) - Account for `python_downloads_json_url` in pre-release Python version warnings ([#​16737](astral-sh/uv#16737)) - Support HTTP/HTTPS URLs in `uv python --python-downloads-json-url` ([#​16542](astral-sh/uv#16542)) ##### Preview features - Add support for `--upgrade` in `uv python install` ([#​16676](astral-sh/uv#16676)) - Fix handling of `python install --default` for pre-release Python versions ([#​16706](astral-sh/uv#16706)) - Add `uv workspace list` to list workspace members ([#​16691](astral-sh/uv#16691)) ##### Bug fixes - Don't check file URLs for ambiguously parsed credentials ([#​16759](astral-sh/uv#16759)) ##### Documentation - Add a "storage" reference document ([#​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=-->
continuation PR based on #14687