Compare commits

...

16 commits
0.7.19 ... main

Author SHA1 Message Date
renovate[bot]
ddb1577a93
Update Rust crate reqwest to v0.12.22 (#14475)
Some checks are pending
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [reqwest](https://redirect.github.com/seanmonstar/reqwest) |
workspace.dependencies | patch | `=0.12.15` -> `=0.12.22` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>seanmonstar/reqwest (reqwest)</summary>

###
[`v0.12.22`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01222)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.21...v0.12.22)

- Fix socks proxies when resolving IPv6 destinations.

###
[`v0.12.21`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01221)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.20...v0.12.21)

- Fix socks proxy to use `socks4a://` instead of `socks4h://`.
- Fix `Error::is_timeout()` to check for hyper and IO timeouts too.
- Fix request `Error` to again include URLs when possible.
- Fix socks connect error to include more context.
- (wasm) implement `Default` for `Body`.

###
[`v0.12.20`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01220)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.19...v0.12.20)

- Add `ClientBuilder::tcp_user_timeout(Duration)` option to set
`TCP_USER_TIMEOUT`.
- Fix proxy headers only using the first matched proxy.
- (wasm) Fix re-adding `Error::is_status()`.

###
[`v0.12.19`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01219)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.18...v0.12.19)

- Fix redirect that changes the method to GET should remove payload
headers.
- Fix redirect to only check the next scheme if the policy action is to
follow.
- (wasm) Fix compilation error if `cookies` feature is enabled (by the
way, it's a noop feature in wasm).

###
[`v0.12.18`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01218)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.17...v0.12.18)

- Fix compilation when `socks` enabled without TLS.

###
[`v0.12.17`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01217)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.16...v0.12.17)

- Fix compilation on macOS.

###
[`v0.12.16`](https://redirect.github.com/seanmonstar/reqwest/blob/HEAD/CHANGELOG.md#v01216)

[Compare
Source](https://redirect.github.com/seanmonstar/reqwest/compare/v0.12.15...v0.12.16)

- Add `ClientBuilder::http3_congestion_bbr()` to enable BBR congestion
control.
- Add `ClientBuilder::http3_send_grease()` to configure whether to send
use QUIC grease.
- Add `ClientBuilder::http3_max_field_section_size()` to configure the
maximum response headers.
- Add `ClientBuilder::tcp_keepalive_interval()` to configure TCP probe
interval.
- Add `ClientBuilder::tcp_keepalive_retries()` to configure TCP probe
count.
- Add `Proxy::headers()` to add extra headers that should be sent to a
proxy.
- Fix `redirect::Policy::limit()` which had an off-by-1 error, allowing
1 more redirect than specified.
- Fix HTTP/3 to support streaming request bodies.
- (wasm) Fix null bodies when calling `Response::bytes_stream()`.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

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

---

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


---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

---

Closes #14243

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-07-07 13:39:57 +02:00
John Mumm
d31e6ad7c7
Move fragment preservation test to directly test our redirect handling logic (#14480)
When [updating](https://github.com/astral-sh/uv/pull/14475) to the
latest `reqwest` version, our fragment propagation test broke. That test
was partially testing the `reqwest` behavior, so this PR moves the
fragment test to directly test our logic for constructing redirect
requests.
2025-07-07 12:51:21 +02:00
renovate[bot]
3a77b9cdd9
Update aws-actions/configure-aws-credentials digest to f503a18 (#14473)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| aws-actions/configure-aws-credentials | action | digest | `3d8cba3` ->
`f503a18` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

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

---

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

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 11:31:31 +02:00
renovate[bot]
1d027bd92a
Update pre-commit dependencies (#14474)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[astral-sh/ruff-pre-commit](https://redirect.github.com/astral-sh/ruff-pre-commit)
| repository | patch | `v0.12.1` -> `v0.12.2` |
| [crate-ci/typos](https://redirect.github.com/crate-ci/typos) |
repository | minor | `v1.33.1` -> `v1.34.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

Note: The `pre-commit` manager in Renovate is not supported by the
`pre-commit` maintainers or community. Please do not report any problems
there, instead [create a Discussion in the Renovate
repository](https://redirect.github.com/renovatebot/renovate/discussions/new)
if you have any questions.

---

### Release Notes

<details>
<summary>astral-sh/ruff-pre-commit (astral-sh/ruff-pre-commit)</summary>

###
[`v0.12.2`](https://redirect.github.com/astral-sh/ruff-pre-commit/releases/tag/v0.12.2)

[Compare
Source](https://redirect.github.com/astral-sh/ruff-pre-commit/compare/v0.12.1...v0.12.2)

See: https://github.com/astral-sh/ruff/releases/tag/0.12.2

</details>

<details>
<summary>crate-ci/typos (crate-ci/typos)</summary>

###
[`v1.34.0`](https://redirect.github.com/crate-ci/typos/releases/tag/v1.34.0)

[Compare
Source](https://redirect.github.com/crate-ci/typos/compare/v1.33.1...v1.34.0)

#### \[1.34.0] - 2025-06-30

##### Features

- Updated the dictionary with the [June
2025](https://redirect.github.com/crate-ci/typos/issues/1309) changes

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

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

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 10:36:26 +02:00
renovate[bot]
bb738aeb44
Update Rust crate test-log to v0.2.18 (#14477)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [test-log](https://redirect.github.com/d-e-s-o/test-log) |
dev-dependencies | patch | `0.2.17` -> `0.2.18` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>d-e-s-o/test-log (test-log)</summary>

###
[`v0.2.18`](https://redirect.github.com/d-e-s-o/test-log/blob/HEAD/CHANGELOG.md#0218)

[Compare
Source](https://redirect.github.com/d-e-s-o/test-log/compare/v0.2.17...v0.2.18)

- Improved cooperation with other similar procedural macros to enable
  attribute stacking

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

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

---

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

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 10:04:50 +02:00
renovate[bot]
fc758bb755
Update Rust crate schemars to v1.0.4 (#14476)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [schemars](https://graham.cool/schemars/)
([source](https://redirect.github.com/GREsau/schemars)) |
workspace.dependencies | patch | `1.0.3` -> `1.0.4` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>GREsau/schemars (schemars)</summary>

###
[`v1.0.4`](https://redirect.github.com/GREsau/schemars/blob/HEAD/CHANGELOG.md#104---2025-07-06)

[Compare
Source](https://redirect.github.com/GREsau/schemars/compare/v1.0.3...v1.0.4)

##### Fixed

- Fix `JsonSchema` impl on
[atomic](https://doc.rust-lang.org/std/sync/atomic/) types being ignored
on non-nightly compilers due to a buggy `cfg` check
([https://github.com/GREsau/schemars/issues/453](https://redirect.github.com/GREsau/schemars/issues/453))
- Fix compatibility with minimal dependency versions, e.g. old(-ish)
versions of `syn`
([https://github.com/GREsau/schemars/issues/450](https://redirect.github.com/GREsau/schemars/issues/450))
- Fix derive for empty tuple variants
([https://github.com/GREsau/schemars/issues/455](https://redirect.github.com/GREsau/schemars/issues/455))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

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

---

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

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 10:00:52 +02:00
renovate[bot]
1308c85efe
Update Rust crate async-channel to v2.5.0 (#14478)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-channel](https://redirect.github.com/smol-rs/async-channel) |
workspace.dependencies | minor | `2.3.1` -> `2.5.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the Dependency
Dashboard for more information.

---

### Release Notes

<details>
<summary>smol-rs/async-channel (async-channel)</summary>

###
[`v2.5.0`](https://redirect.github.com/smol-rs/async-channel/blob/HEAD/CHANGELOG.md#Version-250)

[Compare
Source](https://redirect.github.com/smol-rs/async-channel/compare/v2.4.0...v2.5.0)

- Add `Sender::closed()`
([#&#8203;102](https://redirect.github.com/smol-rs/async-channel/issues/102))

###
[`v2.4.0`](https://redirect.github.com/smol-rs/async-channel/blob/HEAD/CHANGELOG.md#Version-240)

[Compare
Source](https://redirect.github.com/smol-rs/async-channel/compare/v2.3.1...v2.4.0)

- Add `Sender::same_channel()` and `Receiver::same_channel()`.
([#&#8203;98](https://redirect.github.com/smol-rs/async-channel/issues/98))
- Add `portable-atomic` feature to support platforms without atomics.
([#&#8203;106](https://redirect.github.com/smol-rs/async-channel/issues/106))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 4am on Monday" (UTC),
Automerge - At any time (no schedule defined).

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

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

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

---

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

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/astral-sh/uv).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMTcuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 09:58:05 +02:00
John Mumm
f609e1ddaf
Document that VerbatimUrl does not preserve original string after serialization (#14456)
Some checks failed
CI / check cache | macos aarch64 (push) Has been cancelled
CI / check system | python on debian (push) Has been cancelled
CI / check system | python on fedora (push) Has been cancelled
CI / check system | python on ubuntu (push) Has been cancelled
CI / check system | python on rocky linux 8 (push) Has been cancelled
CI / check system | python on rocky linux 9 (push) Has been cancelled
CI / check system | graalpy on ubuntu (push) Has been cancelled
CI / check system | pypy on ubuntu (push) Has been cancelled
CI / check system | python on macos aarch64 (push) Has been cancelled
CI / check system | homebrew python on macos aarch64 (push) Has been cancelled
CI / check system | python on macos x86-64 (push) Has been cancelled
CI / check system | python3.10 on windows x86-64 (push) Has been cancelled
CI / check system | python3.10 on windows x86 (push) Has been cancelled
CI / check system | python3.13 on windows x86-64 (push) Has been cancelled
CI / check system | x86-64 python3.13 on windows aarch64 (push) Has been cancelled
CI / check system | aarch64 python3.13 on windows aarch64 (push) Has been cancelled
CI / check system | windows registry (push) Has been cancelled
CI / check system | python3.12 via chocolatey (push) Has been cancelled
CI / check system | python3.9 via pyenv (push) Has been cancelled
CI / check system | python3.13 (push) Has been cancelled
CI / check system | conda3.11 on macos aarch64 (push) Has been cancelled
CI / check system | conda3.8 on macos aarch64 (push) Has been cancelled
CI / check system | conda3.11 on linux x86-64 (push) Has been cancelled
CI / check system | conda3.8 on linux x86-64 (push) Has been cancelled
CI / check system | conda3.11 on windows x86-64 (push) Has been cancelled
CI / check system | conda3.8 on windows x86-64 (push) Has been cancelled
CI / check system | amazonlinux (push) Has been cancelled
CI / check system | embedded python3.10 on windows x86-64 (push) Has been cancelled
CI / benchmarks | walltime aarch64 linux (push) Has been cancelled
CI / benchmarks | instrumented (push) Has been cancelled
This came up in
[discussion](https://github.com/astral-sh/uv/pull/14387#issuecomment-3032223670)
on #14387.
2025-07-04 22:42:56 +02:00
Tim de Jager
eaf517efd8
Add method to get packages involved in a NoSolutionError (#14457)
Some checks are pending
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

<!-- What's the purpose of the change? What does it do, and why? -->

In pixi we overlay the PyPI packages over the conda packages and we
sometimes need to figure out what PyPI packages are involved in the
no-solution error. We could parse the error message, but this is pretty
error-prone, so it would be good to get access to more information. A
lot of information in this module is private and should probably stay
this way, but package names are easy enough to expose. This would help
us a lot!

I collect into a HashSet to remove duplication, and did not want to
expose a rustc_hash datastructure directly, thats's why I've chosen to
expose as an iterator :)

Let me know if any changes need to be done, and thanks!

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-04 18:08:23 +00:00
Charlie Marsh
e8bc3950ef
Remove transparent variants in uv-extract to enable retries (#14450)
Some checks are pending
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
## Summary

We think this is the culprit for the lack of retries in some settings
(e.g., Python downloads).

See: https://github.com/astral-sh/uv/issues/14425.
2025-07-03 23:32:07 +00:00
konsti
06af93fce7
Fix optional cfg gates (#14448)
Running `cargo clippy` in individual crates could raise warnings due to
unused imports as `Cow` is only used with `#[cfg(feature = "schemars")]`
2025-07-03 15:29:03 -05:00
Simon Sure
8afbd86f03
make ErrorTree for NoSolutionError externally accessible (#14444)
Some checks are pending
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Hey, are you okay with exposing the `ErrorTree` for library consumers?

We have a use case that needs more information on conflicts. We need the
tree-structure of the conflict and be able to traverse it in particular.

Signed-off-by: Simon Sure <ssure@palantir.com>
2025-07-03 11:43:59 -05:00
konsti
a1cda6213c
Make "exit code" -> "exit status" a default filter (#14441)
Remove some test boilerplate.

Revival of https://github.com/astral-sh/uv/pull/14439 with main as base.
2025-07-03 13:50:40 +00:00
konsti
39cdfe9981
Add a test for --force-pep517 (#14310)
There was previously a gap in the test coverage in ensuring that
`--force-pep517` was respected.
2025-07-03 13:34:44 +00:00
Zanie Blue
85c0fc963b
Fix forced resolution with all extras in uv version (#14434)
Closes https://github.com/astral-sh/uv/issues/14433

Same as https://github.com/astral-sh/uv/pull/13380
2025-07-03 07:29:59 -05:00
Zanie Blue
c3f13d2505
Finish incomplete sentence in pip migration guide (#14432)
Some checks are pending
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | aarch64 windows implicit (push) Blocked by required conditions
CI / integration test | aarch64 windows explicit (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | registries (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Fixes https://github.com/astral-sh/uv/pull/12382#discussion_r2181237729
2025-07-03 01:02:17 +00:00
32 changed files with 299 additions and 207 deletions

View file

@ -1585,7 +1585,7 @@ jobs:
run: chmod +x ./uv
- name: "Configure AWS credentials"
uses: aws-actions/configure-aws-credentials@3d8cba388a057b13744d61818a337e40a119b1a7
uses: aws-actions/configure-aws-credentials@f503a1870408dcf2c35d5c2b8a68e69211042c7d
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

View file

@ -12,7 +12,7 @@ repos:
- id: validate-pyproject
- repo: https://github.com/crate-ci/typos
rev: v1.33.1
rev: v1.34.0
hooks:
- id: typos
@ -42,7 +42,7 @@ repos:
types_or: [yaml, json5]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.1
rev: v0.12.2
hooks:
- id: ruff-format
- id: ruff

115
Cargo.lock generated
View file

@ -189,9 +189,9 @@ dependencies = [
[[package]]
name = "async-channel"
version = "2.3.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
dependencies = [
"concurrent-queue",
"event-listener-strategy",
@ -1165,9 +1165,9 @@ dependencies = [
[[package]]
name = "event-listener-strategy"
version = "0.5.3"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
dependencies = [
"event-listener",
"pin-project-lite",
@ -1698,7 +1698,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots",
"webpki-roots 0.26.8",
]
[[package]]
@ -1707,6 +1707,7 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-core",
@ -1714,7 +1715,9 @@ dependencies = [
"http",
"http-body",
"hyper",
"ipnet",
"libc",
"percent-encoding",
"pin-project-lite",
"socket2",
"tokio",
@ -1945,6 +1948,16 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "iri-string"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "is-terminal"
version = "0.4.15"
@ -3062,9 +3075,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.15"
version = "0.12.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
dependencies = [
"async-compression",
"base64 0.22.1",
@ -3079,18 +3092,14 @@ dependencies = [
"hyper",
"hyper-rustls",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"mime_guess",
"once_cell",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-native-certs",
"rustls-pemfile",
"rustls-pki-types",
"serde",
"serde_json",
@ -3098,17 +3107,16 @@ dependencies = [
"sync_wrapper",
"tokio",
"tokio-rustls",
"tokio-socks",
"tokio-util",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots",
"windows-registry 0.4.0",
"webpki-roots 1.0.1",
]
[[package]]
@ -3351,15 +3359,6 @@ dependencies = [
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.11.0"
@ -3428,9 +3427,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d"
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
dependencies = [
"dyn-clone",
"ref-cast",
@ -3442,9 +3441,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b13ed22d6d49fe23712e068770b5c4df4a693a2b02eeff8e7ca3135627a24f6"
checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
dependencies = [
"proc-macro2",
"quote",
@ -3968,9 +3967,9 @@ dependencies = [
[[package]]
name = "test-log"
version = "0.2.17"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f"
checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b"
dependencies = [
"test-log-macros",
"tracing-subscriber",
@ -3978,9 +3977,9 @@ dependencies = [
[[package]]
name = "test-log-macros"
version = "0.2.17"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f"
checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
dependencies = [
"proc-macro2",
"quote",
@ -4172,18 +4171,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-socks"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f"
dependencies = [
"either",
"futures-util",
"thiserror 1.0.69",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.17"
@ -4266,6 +4253,24 @@ dependencies = [
"tower-service",
]
[[package]]
name = "tower-http"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [
"bitflags 2.9.1",
"bytes",
"futures-util",
"http",
"http-body",
"iri-string",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
@ -5635,7 +5640,7 @@ dependencies = [
"uv-trampoline-builder",
"uv-warnings",
"which",
"windows-registry 0.5.3",
"windows-registry",
"windows-result 0.3.4",
"windows-sys 0.59.0",
]
@ -5839,7 +5844,7 @@ dependencies = [
"tracing",
"uv-fs",
"uv-static",
"windows-registry 0.5.3",
"windows-registry",
"windows-result 0.3.4",
"windows-sys 0.59.0",
]
@ -6221,6 +6226,15 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "weezl"
version = "0.1.8"
@ -6448,17 +6462,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-registry"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result 0.3.4",
"windows-strings 0.3.1",
"windows-targets 0.53.0",
]
[[package]]
name = "windows-registry"
version = "0.5.3"

View file

@ -142,7 +142,7 @@ ref-cast = { version = "1.0.24" }
reflink-copy = { version = "0.1.19" }
regex = { version = "1.10.6" }
regex-automata = { version = "0.4.8", default-features = false, features = ["dfa-build", "dfa-search", "perf", "std", "syntax"] }
reqwest = { version = "=0.12.15", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
reqwest = { version = "0.12.22", default-features = false, features = ["json", "gzip", "deflate", "zstd", "stream", "rustls-tls", "rustls-tls-native-roots", "socks", "multipart", "http2", "blocking"] }
reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8", features = ["multipart"] }
reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" }
rkyv = { version = "0.8.8", features = ["bytecheck"] }

View file

@ -982,6 +982,45 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn test_redirect_preserves_fragment() -> Result<()> {
for status in &[301, 302, 303, 307, 308] {
let server = MockServer::start().await;
Mock::given(method("GET"))
.respond_with(
ResponseTemplate::new(*status)
.insert_header("location", format!("{}/redirect", server.uri())),
)
.mount(&server)
.await;
let request = Client::new()
.get(format!("{}#fragment", server.uri()))
.build()
.unwrap();
let response = Client::builder()
.redirect(reqwest::redirect::Policy::none())
.build()
.unwrap()
.execute(request.try_clone().unwrap())
.await
.unwrap();
let redirect_request =
request_into_redirect(request, &response, CrossOriginCredentialsPolicy::Secure)?
.unwrap();
assert!(
redirect_request
.url()
.fragment()
.is_some_and(|fragment| fragment == "fragment")
);
}
Ok(())
}
#[tokio::test]
async fn test_redirect_removes_authorization_header_on_cross_origin() -> Result<()> {
for status in &[301, 302, 303, 307, 308] {

View file

@ -1416,44 +1416,6 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn test_redirect_preserve_fragment() -> Result<(), Error> {
let redirect_server = MockServer::start().await;
// Configure the redirect server to respond with a 307 with a relative URL.
Mock::given(method("GET"))
.respond_with(ResponseTemplate::new(307).insert_header("Location", "/foo".to_string()))
.mount(&redirect_server)
.await;
Mock::given(method("GET"))
.and(path_regex("/foo"))
.respond_with(ResponseTemplate::new(200))
.mount(&redirect_server)
.await;
let cache = Cache::temp()?;
let registry_client = RegistryClientBuilder::new(cache).build();
let client = registry_client.cached_client().uncached();
let mut url = DisplaySafeUrl::parse(&redirect_server.uri())?;
url.set_fragment(Some("fragment"));
assert_eq!(
client
.for_host(&url)
.get(Url::from(url.clone()))
.send()
.await?
.url()
.to_string(),
format!("{}/foo#fragment", redirect_server.uri()),
"Requests should preserve fragment"
);
Ok(())
}
#[test]
fn ignore_failing_files() {
// 1.7.7 has an invalid requires-python field (double comma), 1.7.8 is valid

View file

@ -1,4 +1,6 @@
use std::{borrow::Cow, str::FromStr};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::str::FromStr;
use uv_pep508::PackageName;

View file

@ -1,5 +1,6 @@
use std::str::FromStr;
use std::{borrow::Cow, fmt::Formatter};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::{fmt::Formatter, str::FromStr};
use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError};

View file

@ -1,5 +1,7 @@
use serde::{Deserialize, Deserializer};
use std::{borrow::Cow, str::FromStr};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::str::FromStr;
use url::Url;
/// A host specification (wildcard, or host, with optional scheme and/or port) for which

View file

@ -3,7 +3,9 @@
//! flags set.
use serde::{Deserialize, Deserializer, Serialize};
use std::{borrow::Cow, path::Path};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::path::Path;
use crate::{Index, IndexUrl};

View file

@ -1,4 +1,6 @@
use std::{borrow::Cow, ops::Deref};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::ops::Deref;
use http::StatusCode;
use rustc_hash::FxHashSet;

View file

@ -2,11 +2,11 @@ use std::{ffi::OsString, path::PathBuf};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
#[error("Failed to read from zip file")]
Zip(#[from] zip::result::ZipError),
#[error(transparent)]
#[error("Failed to read from zip file")]
AsyncZip(#[from] async_zip::error::ZipError),
#[error(transparent)]
#[error("I/O operation failed during extraction")]
Io(#[from] std::io::Error),
#[error(
"The top-level of the archive must only contain a list directory, but it contains: {0:?}"

View file

@ -18,11 +18,16 @@ use uv_redacted::DisplaySafeUrl;
use crate::Pep508Url;
/// A wrapper around [`Url`] that preserves the original string.
///
/// The original string is not preserved after serialization/deserialization.
#[derive(Debug, Clone, Eq)]
pub struct VerbatimUrl {
/// The parsed URL.
url: DisplaySafeUrl,
/// The URL as it was provided by the user.
///
/// Even if originally set, this will be [`None`] after
/// serialization/deserialization.
given: Option<ArcStr>,
}

View file

@ -1,3 +1,4 @@
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::fmt::{Display, Formatter};
use std::ops::Deref;

View file

@ -3,6 +3,7 @@ use std::fmt::Formatter;
use std::sync::Arc;
use indexmap::IndexSet;
use itertools::Itertools;
use owo_colors::OwoColorize;
use pubgrub::{
DefaultStringReporter, DerivationTree, Derived, External, Range, Ranges, Reporter, Term,
@ -156,7 +157,7 @@ impl<T> From<tokio::sync::mpsc::error::SendError<T>> for ResolveError {
}
}
pub(crate) type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>;
pub type ErrorTree = DerivationTree<PubGrubPackage, Range<Version>, UnavailableReason>;
/// A wrapper around [`pubgrub::error::NoSolutionError`] that displays a resolution failure report.
pub struct NoSolutionError {
@ -367,6 +368,11 @@ impl NoSolutionError {
NoSolutionHeader::new(self.env.clone())
}
/// Get the conflict derivation tree for external analysis
pub fn derivation_tree(&self) -> &ErrorTree {
&self.error
}
/// Hint at limiting the resolver environment if universal resolution failed for a target
/// that is not the current platform or not the current Python version.
fn hint_disjoint_targets(&self, f: &mut Formatter) -> std::fmt::Result {
@ -404,6 +410,15 @@ impl NoSolutionError {
}
Ok(())
}
/// Get the packages that are involved in this error.
pub fn packages(&self) -> impl Iterator<Item = &PackageName> {
self.error
.packages()
.into_iter()
.filter_map(|p| p.name())
.unique()
}
}
impl std::fmt::Debug for NoSolutionError {

View file

@ -1,4 +1,6 @@
use std::{borrow::Cow, str::FromStr};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::str::FromStr;
use jiff::{Timestamp, ToSpan, tz::TimeZone};

View file

@ -1,5 +1,5 @@
pub use dependency_mode::DependencyMode;
pub use error::{NoSolutionError, NoSolutionHeader, ResolveError, SentinelRange};
pub use error::{ErrorTree, NoSolutionError, NoSolutionHeader, ResolveError, SentinelRange};
pub use exclude_newer::ExcludeNewer;
pub use exclusions::Exclusions;
pub use flat_index::{FlatDistributions, FlatIndex};
@ -54,7 +54,7 @@ mod options;
mod pins;
mod preferences;
mod prerelease;
mod pubgrub;
pub mod pubgrub;
mod python_requirement;
mod redirect;
mod resolution;

View file

@ -1,6 +1,6 @@
pub(crate) use crate::pubgrub::dependencies::PubGrubDependency;
pub(crate) use crate::pubgrub::distribution::PubGrubDistribution;
pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
pub use crate::pubgrub::package::{PubGrubPackage, PubGrubPackageInner, PubGrubPython};
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority, PubGrubTiebreaker};
pub(crate) use crate::pubgrub::report::PubGrubReportFormatter;

View file

@ -9,7 +9,7 @@ use crate::python_requirement::PythonRequirement;
/// [`Arc`] wrapper around [`PubGrubPackageInner`] to make cloning (inside PubGrub) cheap.
#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub(crate) struct PubGrubPackage(Arc<PubGrubPackageInner>);
pub struct PubGrubPackage(Arc<PubGrubPackageInner>);
impl Deref for PubGrubPackage {
type Target = PubGrubPackageInner;
@ -39,7 +39,7 @@ impl From<PubGrubPackageInner> for PubGrubPackage {
/// package (e.g., `black[colorama]`), and mark it as a dependency of the real package (e.g.,
/// `black`). We then discard the virtual packages at the end of the resolution process.
#[derive(Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub(crate) enum PubGrubPackageInner {
pub enum PubGrubPackageInner {
/// The root package, which is used to start the resolution process.
Root(Option<PackageName>),
/// A Python version.
@ -295,7 +295,7 @@ impl PubGrubPackage {
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Hash, Ord)]
pub(crate) enum PubGrubPython {
pub enum PubGrubPython {
/// The Python version installed in the current environment.
Installed,
/// The Python version for which dependencies are being resolved.

View file

@ -7,7 +7,7 @@ use uv_platform_tags::{AbiTag, Tags};
/// The reason why a package or a version cannot be used.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum UnavailableReason {
pub enum UnavailableReason {
/// The entire package cannot be used.
Package(UnavailablePackage),
/// A single version cannot be used.
@ -29,7 +29,7 @@ impl Display for UnavailableReason {
/// Most variant are from [`MetadataResponse`] without the error source, since we don't format
/// the source and we want to merge unavailable messages across versions.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum UnavailableVersion {
pub enum UnavailableVersion {
/// Version is incompatible because it has no usable distributions
IncompatibleDist(IncompatibleDist),
/// The wheel metadata was found, but could not be parsed.
@ -123,7 +123,7 @@ impl From<&MetadataUnavailable> for UnavailableVersion {
/// The package is unavailable and cannot be used.
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) enum UnavailablePackage {
pub enum UnavailablePackage {
/// Index lookups were disabled (i.e., `--no-index`) and the package was not found in a flat index (i.e. from `--find-links`).
NoIndex,
/// Network requests were disabled (i.e., `--offline`), and the package was not found in the cache.

View file

@ -6,6 +6,7 @@
//!
//! Then lowers them into a dependency specification.
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::Formatter;

View file

@ -385,7 +385,7 @@ async fn lock_and_sync(
let default_groups = default_dependency_groups(project.pyproject_toml())?;
let default_extras = DefaultExtras::default();
let groups = DependencyGroups::default().with_defaults(default_groups);
let extras = ExtrasSpecification::from_all_extras().with_defaults(default_extras);
let extras = ExtrasSpecification::default().with_defaults(default_extras);
let install_options = InstallOptions::default();
// Convert to an `AddTarget` by attaching the appropriate interpreter or environment.

View file

@ -15,7 +15,7 @@ fn build_basic() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -133,7 +133,7 @@ fn build_sdist() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -189,7 +189,7 @@ fn build_wheel() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -245,7 +245,7 @@ fn build_sdist_wheel() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -303,7 +303,7 @@ fn build_wheel_from_sdist() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -412,7 +412,7 @@ fn build_fail() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -488,7 +488,6 @@ fn build_workspace() -> Result<()> {
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"\\\.", ""),
(r"\[project\]", "[PKG]"),
(r"\[member\]", "[PKG]"),
@ -694,7 +693,6 @@ fn build_all_with_failure() -> Result<()> {
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"\\\.", ""),
(r"\[project\]", "[PKG]"),
(r"\[member-\w+\]", "[PKG]"),
@ -840,7 +838,7 @@ fn build_constraints() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -901,7 +899,7 @@ fn build_sha() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -1187,7 +1185,7 @@ fn build_tool_uv_sources() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let build = context.temp_dir.child("backend");
@ -1337,7 +1335,6 @@ fn build_non_package() -> Result<()> {
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"\\\.", ""),
(r"\[project\]", "[PKG]"),
(r"\[member\]", "[PKG]"),
@ -1930,7 +1927,7 @@ fn build_with_nonnormalized_name() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([(r"exit code: 1", "exit status: 1"), (r"\\\.", "")])
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
@ -1981,3 +1978,60 @@ fn build_with_nonnormalized_name() -> Result<()> {
Ok(())
}
/// Check that `--force-pep517` is respected.
///
/// The error messages for a broken project are different for direct builds vs. PEP 517.
#[test]
fn force_pep517() -> Result<()> {
// We need to use a real `uv_build` package.
let context = TestContext::new("3.12").with_exclude_newer("2025-05-27T00:00:00Z");
context
.init()
.arg("--build-backend")
.arg("uv")
.assert()
.success();
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
version = "1.0.0"
[tool.uv.build-backend]
module-name = "does_not_exist"
[build-system]
requires = ["uv_build>=0.5.15,<10000"]
build-backend = "uv_build"
"#})?;
uv_snapshot!(context.filters(), context.build().env("RUST_BACKTRACE", "0"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
Building source distribution (uv build backend)...
× Failed to build `[TEMP_DIR]/`
Expected a Python module at: `src/does_not_exist/__init__.py`
");
uv_snapshot!(context.filters(), context.build().arg("--force-pep517").env("RUST_BACKTRACE", "0"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
Building source distribution...
Error: Missing module directory for `does_not_exist` in `src`. Found: `temp`
× Failed to build `[TEMP_DIR]/`
The build backend returned an error
Call to `uv_build.build_sdist` failed (exit status: 1)
hint: This usually indicates a problem with the package or the build environment.
");
Ok(())
}

View file

@ -517,6 +517,8 @@ impl TestContext {
if cfg!(windows) {
filters.push((" --link-mode <LINK_MODE>".to_string(), String::new()));
filters.push((r#"link-mode = "copy"\n"#.to_string(), String::new()));
// Unix uses "exit status", Windows uses "exit code"
filters.push((r"exit code: ".to_string(), "exit status: ".to_string()));
}
filters.extend(

View file

@ -7246,10 +7246,7 @@ fn fail_to_add_revert_project() -> Result<()> {
.child("setup.py")
.write_str("1/0")?;
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.add().arg("./child"), @r#"
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#"
success: false
exit_code: 1
----- stdout -----
@ -7351,10 +7348,7 @@ fn fail_to_edit_revert_project() -> Result<()> {
.child("setup.py")
.write_str("1/0")?;
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.add().arg("./child"), @r#"
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#"
success: false
exit_code: 1
----- stdout -----

View file

@ -23617,10 +23617,7 @@ fn lock_derivation_chain_prod() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.lock(), @r###"
@ -23677,10 +23674,7 @@ fn lock_derivation_chain_extra() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.lock(), @r###"
@ -23739,10 +23733,7 @@ fn lock_derivation_chain_group() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.lock(), @r###"
@ -23812,10 +23803,7 @@ fn lock_derivation_chain_extended() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.lock(), @r###"

View file

@ -14679,10 +14679,7 @@ fn compile_derivation_chain() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_compile().arg("pyproject.toml"), @r###"

View file

@ -342,10 +342,7 @@ dependencies = ["flask==1.0.x"]
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("./path_dep")?;
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install()
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.txt"), @r###"
success: false
@ -4930,10 +4927,7 @@ fn no_build_isolation() -> Result<()> {
requirements_in.write_str("anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz")?;
// We expect the build to fail, because `setuptools` is not installed.
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install()
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.in")
.arg("--no-build-isolation"), @r###"
@ -5001,10 +4995,7 @@ fn respect_no_build_isolation_env_var() -> Result<()> {
requirements_in.write_str("anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz")?;
// We expect the build to fail, because `setuptools` is not installed.
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install()
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.in")
.env(EnvVars::UV_NO_BUILD_ISOLATION, "yes"), @r###"
@ -8601,10 +8592,7 @@ fn install_build_isolation_package() -> Result<()> {
)?;
// Running `uv pip install` should fail for iniconfig.
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install()
uv_snapshot!(context.filters(), context.pip_install()
.arg("--no-build-isolation-package")
.arg("iniconfig")
.arg(package.path()), @r###"
@ -8931,10 +8919,7 @@ fn missing_top_level() {
fn sklearn() {
let context = TestContext::new("3.12");
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install().arg("sklearn"), @r###"
uv_snapshot!(context.filters(), context.pip_install().arg("sklearn"), @r###"
success: false
exit_code: 1
----- stdout -----
@ -8984,10 +8969,7 @@ fn resolve_derivation_chain() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.pip_install()

View file

@ -1122,10 +1122,7 @@ fn sync_build_isolation_package() -> Result<()> {
)?;
// Running `uv sync` should fail for iniconfig.
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(filters, context.sync().arg("--no-build-isolation-package").arg("source-distribution"), @r###"
uv_snapshot!(context.filters(), context.sync().arg("--no-build-isolation-package").arg("source-distribution"), @r###"
success: false
exit_code: 1
----- stdout -----
@ -1215,10 +1212,7 @@ fn sync_build_isolation_extra() -> Result<()> {
)?;
// Running `uv sync` should fail for the `compile` extra.
let filters = std::iter::once((r"exit code: 1", "exit status: 1"))
.chain(context.filters())
.collect::<Vec<_>>();
uv_snapshot!(&filters, context.sync().arg("--extra").arg("compile"), @r###"
uv_snapshot!(context.filters(), context.sync().arg("--extra").arg("compile"), @r###"
success: false
exit_code: 1
----- stdout -----
@ -1239,7 +1233,7 @@ fn sync_build_isolation_extra() -> Result<()> {
"###);
// Running `uv sync` with `--all-extras` should also fail.
uv_snapshot!(&filters, context.sync().arg("--all-extras"), @r###"
uv_snapshot!(context.filters(), context.sync().arg("--all-extras"), @r###"
success: false
exit_code: 1
----- stdout -----
@ -6985,10 +6979,7 @@ fn sync_derivation_chain() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.sync(), @r###"
@ -7051,10 +7042,7 @@ fn sync_derivation_chain_extra() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.sync().arg("--extra").arg("wsgi"), @r###"
@ -7119,10 +7107,7 @@ fn sync_derivation_chain_group() -> Result<()> {
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"/.*/src", "/[TMP]/src"),
])
.chain([(r"/.*/src", "/[TMP]/src")])
.collect::<Vec<_>>();
uv_snapshot!(filters, context.sync().arg("--group").arg("wsgi"), @r###"

View file

@ -1682,7 +1682,6 @@ fn tool_install_uninstallable() {
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"bdist\.[^/\\\s]+(-[^/\\\s]+)?", "bdist.linux-x86_64"),
(r"\\\.", ""),
(r"#+", "#"),

View file

@ -1958,3 +1958,57 @@ fn version_set_evil_constraints() -> Result<()> {
Ok(())
}
/// Bump the version with conflicting extras, to ensure we're activating the correct subset of
/// extras during the resolve.
#[test]
fn version_extras() -> Result<()> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "myproject"
version = "1.10.31"
requires-python = ">=3.12"
[project.optional-dependencies]
foo = ["requests"]
bar = ["httpx"]
baz = ["flask"]
[tool.uv]
conflicts = [[{"extra" = "foo"}, {"extra" = "bar"}]]
"#,
)?;
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("patch"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 1.10.31 => 1.10.32
----- stderr -----
Resolved 19 packages in [TIME]
Audited in [TIME]
");
// Sync an extra, we should not remove it.
context.sync().arg("--extra").arg("foo").assert().success();
uv_snapshot!(context.filters(), context.version()
.arg("--bump").arg("patch"), @r"
success: true
exit_code: 0
----- stdout -----
myproject 1.10.32 => 1.10.33
----- stderr -----
Resolved 19 packages in [TIME]
Audited in [TIME]
");
Ok(())
}

View file

@ -324,7 +324,7 @@ so multiple files are not needed to lock development dependencies.
The uv lockfile is always [universal](../../concepts/resolution.md#universal-resolution), so
multiple files are not needed to
[lock dependencies for each platform](#platform-specific-dependencies). This ensures that all
developers
developers are using consistent, locked versions of dependencies regardless of their machine.
The uv lockfile also supports concepts like
[pinning packages to specific indexes](../../concepts/indexes.md#pinning-a-package-to-an-index),