Compare commits

...

588 commits
0.7.6 ... main

Author SHA1 Message Date
konsti
2ad924d4cf
Use consistent workspace inheritance (#15031)
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 | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.13 (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 | amazonlinux (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 | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (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 / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
Following a CI failure in https://github.com/astral-sh/uv/pull/15028,
ensure that all workspace crates are inheriting the MSRV and other
workspace configuration from the workspace root.
2025-08-02 22:03:51 +02:00
Charlie Marsh
a981e92d31
Remove some arguments from install (#15033)
## Summary

We can read these from `BuildDispatch`.
2025-08-02 19:38:39 +00:00
Charlie Marsh
3a7aeff86f
Respect extra build requires when reading from wheel cache (#15030)
## Summary

We weren't including these in the cache key when constructing the
install plan. We likely still read them from the cache later, but we may
have reported the wrong number of prepares, etc.
2025-08-02 19:26:02 +00:00
konsti
368b7b1e12
Fix some nightly lints (#15028)
Apply fixes for some `cargo check` and `cargo clippy` lints that are on
in nightly Rust.

The following command now passes, the blanket allows had to many
false-positives:

```
cargo +nightly clippy -- -A clippy::doc_markdown -A mismatched_lifetime_syntaxes -A clippy::explicit_deref_methods
```

`cargo +nightly check -- -A mismatched_lifetime_syntaxes` now passes
without warnings.
2025-08-02 18:59:23 +00:00
Charlie Marsh
025d209735
Move cache sharding below prepare_metadata_for_build_wheel (#15029)
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
## Summary

No change in behavior. This logic just isn't needed until the next
block, and as-written, it's hard to tell.
2025-08-02 14:08:49 -04:00
Wang Bing-hua
3dc921d89c
Gracefully handle entrypoint permission errors (#15026)
Gracefully handle entrypoint permission errors

`uv run --with` could fail with a "permission denied" error when it
tried to copy an entrypoint with restrictive permissions.

For instance:

```sh
$ stat -c '%A' /usr/bin/groupmems
-rwxr-s---

$ uv python find
/usr/bin/python

$ uv run --with dummy_test
error: failed to open file `/usr/bin/groupmems`: Permission denied (os error 13)
```

The entrypoint copying logic now catches these permission errors and
skips the file, making `uv` more resilient on systems with binaries that
have restrictive permissions.
2025-08-02 07:03:37 -05:00
William Woodruff
34b5afcba6
chore(ci): address findings in publish-docs workflow (#15018)
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 | conda3.8 on linux x86-64 (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.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
2025-08-01 16:10:58 -04:00
William Woodruff
0b3c32c15b
chore(ci): pin some lingering actions by hash (#15016) 2025-08-01 15:09:29 -04:00
Charlie Marsh
785595bd35
Remove retry wrapper when matching on error kind (#14996)
Some checks failed
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 | pyston (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 | windows registry (push) Has been cancelled
CI / check system | python3.13 (push) Has been cancelled
CI / check system | conda3.8 on linux x86-64 (push) Has been cancelled
CI / check system | conda3.8 on windows x86-64 (push) Has been cancelled
CI / check system | aarch64 python3.13 on windows aarch64 (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 | 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.11 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
## Summary

We often match on `ErrorKind` to figure out how to handle an error
(e.g., to treat a 404 as "Not found" rather than aborting the program).
Unfortunately, if we retry, we wrap the error in a new kind that
includes the retry count. This PR adds an unwrapping mechanism to ensure
that callers always look at the underlying error.

Closes https://github.com/astral-sh/uv/issues/14941.

Closes https://github.com/astral-sh/uv/issues/14989.
2025-07-31 17:00:01 -04:00
konsti
56677c540a
Log the debug error trace (#14458)
Some checks are pending
CI / check system | python on fedora (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 / 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 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 | conda3.8 on linux x86-64 (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 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 / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
For #14425. We can see the error without `error(transparent)` applied by
looking at the debug representation.
2025-07-31 19:13:09 +02:00
Zanie Blue
1bca8bd044
Add extra-build-dependencies test cases for setuptools (#14998) 2025-07-31 11:17:53 -05:00
Zanie Blue
d867f3e595
Skipcargo dev generate-all test case in CI (#14972)
This means that CI tests fail in a way that is redundant with the
dedicated CI job which can obscure signal on whether actual tests are
failing

e.g.,
4703411653
2025-07-31 15:49:42 +00:00
Charlie Marsh
fa24d9a5e2
Include wheel hashes from local Simple indexes (#14993)
## Summary

This just looks like an oversight. We weren't including hashes from
local Simple API indexes if a package had both a wheel and a source
distribution.

Closes https://github.com/astral-sh/uv/issues/14883
2025-07-31 14:20:49 +00:00
Chisato
538ebe6fcf
Fix symlink preservation in virtual environment creation (#14933)
## Summary

  Fixes inconsistent symlink handling in `uv venv` command (#14670).

## Problem


00efde06b6/crates/uv-virtualenv/src/virtualenv.rs (L81)

The original code used `Path::metadata()` which automatically follows
symlinks, causing the system to treat symlinked virtual environment
paths as regular directories. When a user runs uv venv on an existing
symlinked virtual environment `(.venv -> foo)`, the code incorrectly
treats the symlink as a regular directory because `location.metadata()`
automatically follows the symlink and returns metadata for the target
directory `foo/`. This causes the removal logic to delete the symlink
itself and permanently breaking the symlink relationship and replacing
it with a standard directory structure.
 
## Solution

- Use canonicalize() to resolve symlinks only when removing and
recreating virtual
  environments
- This ensures operations target the actual directory while preserving
the symlink
  structure
- Minimal change that fixes the core issue without complex path
management

## Test Plan

```bash
➜  test-env alias uv-dev='/Users/wingmunfung/workspace/uv/target/debug/uv'
➜  test-env ln -s dummy foo
➜  test-env ln -s foo .venv
➜  test-env ls -lah        
total 0
drwxr-xr-x   4 wingmunfung  staff   128B Jul 30 10:39 .
drwxr-xr-x  48 wingmunfung  staff   1.5K Jul 29 17:08 ..
lrwxr-xr-x   1 wingmunfung  staff     3B Jul 30 10:39 .venv -> foo
lrwxr-xr-x   1 wingmunfung  staff     5B Jul 30 10:39 foo -> dummy
➜  test-env uv-dev venv
Using CPython 3.13.2
Creating virtual environment at: .venv
error: Failed to create virtual environment
  Caused by: failed to create directory `.venv`: File exists (os error 17)
➜  test-env mkdir dummy
➜  test-env uv-dev venv
Using CPython 3.13.2
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
➜  test-env ls -lah
total 0
drwxr-xr-x   5 wingmunfung  staff   160B Jul 30 10:39 .
drwxr-xr-x  48 wingmunfung  staff   1.5K Jul 29 17:08 ..
lrwxr-xr-x   1 wingmunfung  staff     3B Jul 30 10:39 .venv -> foo
drwxr-xr-x   7 wingmunfung  staff   224B Jul 30 10:39 dummy
lrwxr-xr-x   1 wingmunfung  staff     5B Jul 30 10:39 foo -> dummy
➜  test-env uv-dev venv
Using CPython 3.13.2
Creating virtual environment at: .venv
✔ A virtual environment already exists at `.venv`. Do you want to replace it? · yes
Activate with: source .venv/bin/activate
➜  test-env ls -lah
total 0
drwxr-xr-x   5 wingmunfung  staff   160B Jul 30 10:39 .
drwxr-xr-x  48 wingmunfung  staff   1.5K Jul 29 17:08 ..
lrwxr-xr-x   1 wingmunfung  staff     3B Jul 30 10:39 .venv -> foo
drwxr-xr-x@  7 wingmunfung  staff   224B Jul 30 10:39 dummy
lrwxr-xr-x   1 wingmunfung  staff     5B Jul 30 10:39 foo -> dummy

### the symlink still exists
```

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-31 11:59:23 +00:00
Micha Reiser
c4aaae39bc
Improve visibility of copy and line separator in dark mode (#14987)
## Summary

Same as https://github.com/astral-sh/ruff/pull/19630/ but for uv's
documentation

## Test Plan
<img width="884" height="667" alt="Screenshot 2025-07-31 at 08 50 09"
src="https://github.com/user-attachments/assets/ad3a0ad3-b791-416d-865d-a6b618bf6d11"
/>
2025-07-31 06:50:12 -05:00
Charlie Marsh
3564e882d7
Ensure consistent indentation when adding dependencies (#14991)
## Summary

The basic problem here is that when we had multiple items in an inline
array, and that array expanded to multiple lines, we accidentally
changed the indentation part-way through due to how prefixes work in the
TOML.

Here's Claude's explanation of the root cause, which I find pretty
decent:

```
  Here's what happened step by step:

  1. First item ("iniconfig"): Has empty prefix "" → indentation_prefix stays None → uses default 4 spaces
  2. Second item ("ruff"): Has empty prefix "" → indentation_prefix stays None → uses default 4 spaces
  3. Third item ("typing-extensions"): Has prefix " " (single space from inline format) → indentation_prefix becomes
  Some(" ") → uses only 1 space!

  This produced:
  [dependency-groups]
  dev = [
      "iniconfig>=2.0.0",
      "ruff",
   "typing-extensions",  # ← Only 1 space instead of 4!
  ]

  Why the Third Item Had a Different Prefix

  In inline arrays like ["ruff", "typing-extensions"], the items are separated by commas and spaces. When parsed by
  the TOML library:
  - "ruff" has no prefix (it comes right after [)
  - "typing-extensions" has a single space prefix (the space after the comma)

  The Fix

  Moving the indentation calculation outside the loop ensures it's calculated only once:

  // Calculate indentation ONCE before the loop
  if let Some(first_item) = deps.iter().next() {
      let decor_prefix = /* get prefix from first item */
      indentation_prefix = (!decor_prefix.is_empty()).then_some(decor_prefix.to_string());
  }

  // Now use the same indentation for ALL items
  for item in deps.iter_mut() {
      // Apply consistent indentation to every item
  }

  This ensures all items get the same indentation (4 spaces by default when converting from inline arrays), producing
   the correct output:

  [dependency-groups]
  dev = [
      "iniconfig>=2.0.0",
      "ruff",
      "typing-extensions",  # ← Correct 4-space indentation
  ]

  The bug only affected arrays being converted from inline to multiline format, where different items might have
  different residual formatting from their inline representation.
```

Closes #14961.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-31 11:50:05 +00:00
Tim de Jager
fc0f637406
Make the BuildDispatch interpreter method async (#14956)
This is a bit of a weird request, but in [pixi](https://pixi.sh) we are
making use of this function to lazily instantiate a conda environment.
Well, in actuality we are using a shim to the `BuildDispatch` to
actually to only create a conda prefix, if some package needs to be
built during the resolution phase. Otherwise we can resolve everything
without an enviroment containing a python intepreter.

We are using a method now - that uses the runtime to run async code
inside this function, as `interpreter` is the first method called on a
`BuildContext` when running a source build - using
`tokio::Handle::block_on`.
However was causing a deadlock in very specific situations, me and
@baszalmstra + @wolfv have investigated this thoroughly, but have not
been able to find the root cause. It would hang in a part of the uv code
that hits the index, but that is **after** all of our initialization
*and the blocking call* was completed.
Changing this to be fully async fixes the problem, this requires this
method to be async though.

We get that this is not necessarily required, and we might find a
workaround, but I wanted to try it this way first.

Thanks!
2025-07-31 06:42:27 -05:00
Aaron Ang
3df972f18a
Support installing additional executables in uv tool install (#14014)
Some checks are pending
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 | python3.9 via pyenv (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
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 | 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 | conda3.8 on linux x86-64 (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.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
Close #6314

## Summary

Continuing from #7592. Created a new PR to rebase the old branch with
`main`, cleaned up test errors, and improved readability.

## Test Plan

Same test cases as in #7592.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-30 14:50:24 -05:00
Zanie Blue
e176e17144
Bump version to 0.8.4 (#14980)
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
2025-07-30 16:24:20 +00:00
Zanie Blue
630394476e
Copy entrypoints that have a shebang that differs in python vs python3 (#14970)
In https://github.com/astral-sh/uv/issues/14919 it was reported that
uv's behavior differed after the first invocation. I noticed we weren't
copying entrypoints after the first invocation. It turns out the
shebangs were written with `.../python` but on a subsequent invocation
the `sys.executable` was `.../python3` so we didn't detect these as
matching.

This is a pretty naive fix, but it seems much easier than ensuring the
entry point path exactly matches the subsequent `sys.executable` we
find.

I guess we should fix this in reverse too? but I think we might always
prefer `python3` when loading interpreters from environments.

See #14790 for more background.
2025-07-30 11:00:16 -05:00
Zanie Blue
c9d3d60a18
Implement CacheKey for all Pep508Url variants (#14978)
Closes #14973
2025-07-30 10:44:06 -05:00
Charlie Marsh
a76e538aa5
Extend wheel filtering to Android tags (#14977)
## Summary

Just while I'm here for https://github.com/astral-sh/uv/pull/14976.
2025-07-30 15:26:44 +00:00
Charlie Marsh
9b8ff44a04
Perform wheel lockfile filtering based on platform and OS intersection (#14976)
## Summary

Ensures that if the user filters to macOS ARM, we don't include macOS
x86_64 wheels.

Closes https://github.com/astral-sh/uv/issues/14901.
2025-07-30 15:12:22 +00:00
Zanie Blue
6856a27711
Add extra-build-dependencies (#14735)
Replaces https://github.com/astral-sh/uv/pull/14092

Adds `tool.uv.extra-build-dependencies = {package = [dependency, ...]}`
which extends `build-system.requires` during package builds.

These are lowered via workspace sources, are applied to transitive
dependencies, and are included in the wheel cache shard hash.

There are some features we need to follow-up on, but are out of scope
here:

- Preferring locked versions for build dependencies
- Settings for requiring locked versions for build depencies

There are some quality of life follow-ups we should also do:

- Warn on `extra-build-dependencies` that do not apply to any packages
- Add test cases and improve error messaging when the
`extra-build-dependencies` resolve fails


-------

There ~are~ were a few open decisions to be made here

1. Should we resolve these dependencies alongside the
`build-system.requires` dependencies? Or should we resolve separately?
(I think the latter is more powerful? because you can override things?
but it opens the door to breaking your build)
2. Should we install these dependencies into the same environment? Or
should we layer it on top as we do elsewhere? (I think it's fine to
install into the same environment)
3. Should we respect sources defined in the parent project? (I think
yes, but then we need to lower the dependencies earlier — I don't think
that's a big deal, but it's not implemented)
4. Should we respect sources defined in the child project? (I think no,
this gets really complicated and seems weird to allow)
5. Should we apply this to transitive dependencies? (I think so)

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-07-30 09:53:07 -05:00
konsti
17f0c91896
Show uv_build in projects documentation (#14968)
Fix https://github.com/astral-sh/uv/issues/14957
2025-07-30 14:04:07 +02:00
Boseong Choi
b2eff990df
Fix typo in uv-pep440/README.md (#14965)
## Summary

I noticed what appears to be a small typo in the documentation. In the
section describing dev versions, it says `sbpth table releases`. I
believe this was meant to be `both stable releases`, to match the
structure of the previous sentence about post versions.
2025-07-30 12:25:48 +02:00
Charlie Marsh
b31d786fe9
Add UV_ prefix to installer environment variables (#14964)
Some checks are pending
CI / benchmarks | instrumented (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (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 | pypy on ubuntu (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 | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy 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 | python3.9 via pyenv (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.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
## Summary

Available as of https://github.com/astral-sh/cargo-dist/pull/46.
2025-07-30 01:24:59 +00:00
Zanie Blue
e7c8b47b7a
Clarify messaging when a new resolution needs to be performed (#14938)
We do not just "ignore" the existing lockfile here. We retain the
existing messaging for cases where we do actually throw out the
lockfile, like `--upgrade`.
2025-07-29 21:13:30 -04:00
Zanie Blue
11fe8f70f9
Add exclude-newer-package (#14489)
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 ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (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 fedora (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (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 | 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.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 / benchmarks | instrumented (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (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.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
Adds `exclude-newer-package = { package = timestamp, ... } ` and
`--exclude-newer-package package=timestamp`. These take precedence over
`exclude-newer` for a given package.

This does need to be serialized to the lockfile, so the revision is
bumped to 3. I tested a previous version and we can read a lockfile with
this information just fine.

Closes https://github.com/astral-sh/uv/issues/14394
2025-07-29 17:00:25 -05:00
Zanie Blue
00efde06b6
Split platform detection code into a dedicated uv-platform crate (#14918)
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
In service of some subsequent work...
2025-07-28 14:12:04 -05:00
Zanie Blue
5686771464
Cache Python downloads by default in python install tests (#14326)
Adds a cache bucket for Python installs and uses it by default during
tests, extending the opt-in cache added in
https://github.com/astral-sh/uv/pull/12175

Updates the `python_install` tests to use a shared cache for Python
installs. This reduces the `python_install` test runtime on my machine
from 23s -> 17s. The difference should be much larger on machines with
slower internet and less cores for test workers :) This should also
improve stability in CI by reducing reliance on the network during test
runs, see #14327
2025-07-28 17:33:57 +00:00
konsti
ac135278c3
Better warning chain styling (#14934)
Improve the styling of warning chains for Python installation errors.
Apply the same logic to other internal warning and error formatting
locations.

**Before**

<img width="1232" height="364" alt="Screenshot from 2025-07-28 10-06-41"
src="https://github.com/user-attachments/assets/e3befe14-ad4c-44ed-8b0a-57d9c9a3b815"
/>

**After**

<img width="1232" height="364" alt="Screenshot from 2025-07-28 10-23-49"
src="https://github.com/user-attachments/assets/1bd890c1-5dbb-4662-93bd-14430c060a69"
/>
2025-07-28 16:23:39 +00:00
renovate[bot]
90885fd0d9
Update pre-commit hook astral-sh/ruff-pre-commit to v0.12.5 (#14925)
Some checks are pending
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 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 | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows 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 / benchmarks | instrumented (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 (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 | 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 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
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.4` -> `v0.12.5` |

---

> [!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.5`](https://redirect.github.com/astral-sh/ruff-pre-commit/releases/tag/v0.12.5)

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

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

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 08:57:33 -05:00
shikinamiasuka
55df845922
Fix incorrect file permissions in wheel packages (#14930)
Fixes #14920

## Summary

Problem: When building wheel packages, metadata files (such as RECORD,
METADATA, WHEEL, and
license files) were being created with incorrect Unix permissions
(--w--wx---), lacking
  read permissions and having unexpected executable permissions.

Solution: The fix ensures that all metadata files in wheel packages are
created with proper
   644 (rw-r--r--) permissions by:
- Adding explicit unix_permissions(0o644) setting in the write_bytes
method for metadata
  files
  - Updating permission constants to use octal notation for clarity
  - Improving code comments to document the permission settings

Impact: This change ensures wheel packages created by uv have standard
file permissions
consistent with other Python build tools like setuptools, improving
compatibility and
  following Python packaging best practices.
2025-07-28 15:56:08 +02:00
Zanie Blue
c97d12bcf3
Unhide uv from --build-backend options (#14939)
Closes https://github.com/astral-sh/uv/issues/14921
2025-07-28 13:26:23 +00:00
renovate[bot]
8cd8c95071
Update Rust crate criterion to 0.7.0 (#14927)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [criterion](https://bheisler.github.io/criterion.rs/book/index.html)
([source](https://redirect.github.com/bheisler/criterion.rs)) |
dependencies | minor | `0.6.0` -> `0.7.0` |

---

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

---

### Release Notes

<details>
<summary>bheisler/criterion.rs (criterion)</summary>

###
[`v0.7.0`](https://redirect.github.com/bheisler/criterion.rs/blob/HEAD/CHANGELOG.md#070---2025-07-25)

[Compare
Source](https://redirect.github.com/bheisler/criterion.rs/compare/0.6.0...0.7.0)

- Bump version of criterion-plot to align dependencies.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 08:10:06 -05:00
renovate[bot]
d71c65abd4
Update Rust crate tokio to v1.47.0 (#14928)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [tokio](https://tokio.rs)
([source](https://redirect.github.com/tokio-rs/tokio)) |
workspace.dependencies | minor | `1.46.1` -> `1.47.0` |

---

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

---

### Release Notes

<details>
<summary>tokio-rs/tokio (tokio)</summary>

###
[`v1.47.0`](https://redirect.github.com/tokio-rs/tokio/releases/tag/tokio-1.47.0):
Tokio v1.47.0

[Compare
Source](https://redirect.github.com/tokio-rs/tokio/compare/tokio-1.46.1...tokio-1.47.0)

##### 1.47.0 (July 25th, 2025)

This release adds `poll_proceed` and `cooperative` to the `coop` module
for
cooperative scheduling, adds `SetOnce` to the `sync` module which
provides
similar functionality to \[`std::sync::OnceLock`], and adds a new method
`sync::Notify::notified_owned()` which returns an `OwnedNotified`
without
a lifetime parameter.

##### Added

- coop: add `cooperative` and `poll_proceed` ([#&#8203;7405])
- sync: add `SetOnce` ([#&#8203;7418])
- sync: add `sync::Notify::notified_owned()` ([#&#8203;7465])

##### Changed

- deps: upgrade windows-sys 0.52 → 0.59
(\[[#&#8203;7117](https://redirect.github.com/tokio-rs/tokio/issues/7117)])
- deps: update to socket2 v0.6
(\[[#&#8203;7443](https://redirect.github.com/tokio-rs/tokio/issues/7443)])
- sync: improve `AtomicWaker::wake` performance ([#&#8203;7450])

##### Documented

- metrics: fix listed feature requirements for some metrics
([#&#8203;7449])
- runtime: improve safety comments of `Readiness<'_>` ([#&#8203;7415])

[#&#8203;7405]: https://redirect.github.com/tokio-rs/tokio/pull/7405

[#&#8203;7415]: https://redirect.github.com/tokio-rs/tokio/pull/7415

[#&#8203;7418]: https://redirect.github.com/tokio-rs/tokio/pull/7418

[#&#8203;7449]: https://redirect.github.com/tokio-rs/tokio/pull/7449

[#&#8203;7450]: https://redirect.github.com/tokio-rs/tokio/pull/7450

[#&#8203;7465]: https://redirect.github.com/tokio-rs/tokio/pull/7465

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 08:09:38 -05:00
renovate[bot]
a5fdc5319d
Update CodSpeedHQ/action action to v3.8.0 (#14926)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [CodSpeedHQ/action](https://redirect.github.com/CodSpeedHQ/action) |
action | minor | `v3.7.0` -> `v3.8.0` |

---

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

---

### Release Notes

<details>
<summary>CodSpeedHQ/action (CodSpeedHQ/action)</summary>

###
[`v3.8.0`](https://redirect.github.com/CodSpeedHQ/action/releases/tag/v3.8.0)

[Compare
Source](https://redirect.github.com/CodSpeedHQ/action/compare/v3.7.0...v3.8.0)

##### What's Changed

##### <!-- 1 -->🐛 Bug Fixes

- Adjust offset for symbols of module loaded at preferred base by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;97](https://redirect.github.com/CodSpeedHQ/runner/pull/97)
- Run with --scope to allow perf to trace the benchmark process by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Run with bash to support complex scripts by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Execute pre- and post-bench scripts for non-perf walltime runner by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;96](https://redirect.github.com/CodSpeedHQ/runner/pull/96)

##### <!-- 2 -->🏗️ Refactor

- Process memory mappings in separate function by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)

##### <!-- 7 -->⚙️ Internals

- Add debug logs for perf.map collection by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add complex cmd and env tests by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)

**Full Changelog**:
https://github.com/CodSpeedHQ/action/compare/v3.7.0...v3.8.0
**Full Runner Changelog**:
https://github.com/CodSpeedHQ/runner/blob/main/CHANGELOG.md

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 07:50:32 -05:00
renovate[bot]
a1a17718a9
Update taiki-e/install-action action to v2.57.1 (#14929)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[taiki-e/install-action](https://redirect.github.com/taiki-e/install-action)
| action | minor | `v2.56.19` -> `v2.57.1` |

---

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

---

### Release Notes

<details>
<summary>taiki-e/install-action (taiki-e/install-action)</summary>

###
[`v2.57.1`](https://redirect.github.com/taiki-e/install-action/blob/HEAD/CHANGELOG.md#100---2021-12-30)

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.57.0...v2.57.1)

Initial release

[Unreleased]:
https://redirect.github.com/taiki-e/install-action/compare/v2.57.1...HEAD

[2.57.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.57.0...v2.57.1

[2.57.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.24...v2.57.0

[2.56.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.23...v2.56.24

[2.56.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.22...v2.56.23

[2.56.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.21...v2.56.22

[2.56.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.20...v2.56.21

[2.56.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.19...v2.56.20

[2.56.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.18...v2.56.19

[2.56.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.17...v2.56.18

[2.56.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.16...v2.56.17

[2.56.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.15...v2.56.16

[2.56.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.14...v2.56.15

[2.56.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.13...v2.56.14

[2.56.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.12...v2.56.13

[2.56.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.11...v2.56.12

[2.56.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.10...v2.56.11

[2.56.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.9...v2.56.10

[2.56.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.8...v2.56.9

[2.56.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.7...v2.56.8

[2.56.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.6...v2.56.7

[2.56.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.5...v2.56.6

[2.56.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.4...v2.56.5

[2.56.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.3...v2.56.4

[2.56.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.2...v2.56.3

[2.56.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.1...v2.56.2

[2.56.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.56.0...v2.56.1

[2.56.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.55.4...v2.56.0

[2.55.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.55.3...v2.55.4

[2.55.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.55.2...v2.55.3

[2.55.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.55.1...v2.55.2

[2.55.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.55.0...v2.55.1

[2.55.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.54.3...v2.55.0

[2.54.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.54.2...v2.54.3

[2.54.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.54.1...v2.54.2

[2.54.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.54.0...v2.54.1

[2.54.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.53.2...v2.54.0

[2.53.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.53.1...v2.53.2

[2.53.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.53.0...v2.53.1

[2.53.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.8...v2.53.0

[2.52.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.7...v2.52.8

[2.52.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.6...v2.52.7

[2.52.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.5...v2.52.6

[2.52.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.4...v2.52.5

[2.52.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.3...v2.52.4

[2.52.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.2...v2.52.3

[2.52.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.1...v2.52.2

[2.52.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.52.0...v2.52.1

[2.52.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.51.3...v2.52.0

[2.51.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.51.2...v2.51.3

[2.51.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.51.1...v2.51.2

[2.51.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.51.0...v2.51.1

[2.51.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.10...v2.51.0

[2.50.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.9...v2.50.10

[2.50.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.8...v2.50.9

[2.50.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.7...v2.50.8

[2.50.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.6...v2.50.7

[2.50.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.5...v2.50.6

[2.50.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.4...v2.50.5

[2.50.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.3...v2.50.4

[2.50.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.2...v2.50.3

[2.50.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.1...v2.50.2

[2.50.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.50.0...v2.50.1

[2.50.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.50...v2.50.0

[2.49.50]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.49...v2.49.50

[2.49.49]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.48...v2.49.49

[2.49.48]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.47...v2.49.48

[2.49.47]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.46...v2.49.47

[2.49.46]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.45...v2.49.46

[2.49.45]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.44...v2.49.45

[2.49.44]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.43...v2.49.44

[2.49.43]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.42...v2.49.43

[2.49.42]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.41...v2.49.42

[2.49.41]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.40...v2.49.41

[2.49.40]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.39...v2.49.40

[2.49.39]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.38...v2.49.39

[2.49.38]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.37...v2.49.38

[2.49.37]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.36...v2.49.37

[2.49.36]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.35...v2.49.36

[2.49.35]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.34...v2.49.35

[2.49.34]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.33...v2.49.34

[2.49.33]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.32...v2.49.33

[2.49.32]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.31...v2.49.32

[2.49.31]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.30...v2.49.31

[2.49.30]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.29...v2.49.30

[2.49.29]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.28...v2.49.29

[2.49.28]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.27...v2.49.28

[2.49.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.26...v2.49.27

[2.49.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.25...v2.49.26

[2.49.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.24...v2.49.25

[2.49.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.23...v2.49.24

[2.49.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.22...v2.49.23

[2.49.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.21...v2.49.22

[2.49.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.20...v2.49.21

[2.49.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.19...v2.49.20

[2.49.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.18...v2.49.19

[2.49.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.17...v2.49.18

[2.49.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.16...v2.49.17

[2.49.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.15...v2.49.16

[2.49.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.14...v2.49.15

[2.49.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.13...v2.49.14

[2.49.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.12...v2.49.13

[2.49.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.11...v2.49.12

[2.49.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.10...v2.49.11

[2.49.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.9...v2.49.10

[2.49.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.8...v2.49.9

[2.49.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.7...v2.49.8

[2.49.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.6...v2.49.7

[2.49.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.5...v2.49.6

[2.49.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.4...v2.49.5

[2.49.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.3...v2.49.4

[2.49.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.2...v2.49.3

[2.49.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.1...v2.49.2

[2.49.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.49.0...v2.49.1

[2.49.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.22...v2.49.0

[2.48.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.21...v2.48.22

[2.48.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.20...v2.48.21

[2.48.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.19...v2.48.20

[2.48.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.18...v2.48.19

[2.48.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.17...v2.48.18

[2.48.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.16...v2.48.17

[2.48.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.15...v2.48.16

[2.48.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.14...v2.48.15

[2.48.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.13...v2.48.14

[2.48.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.12...v2.48.13

[2.48.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.11...v2.48.12

[2.48.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.10...v2.48.11

[2.48.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.9...v2.48.10

[2.48.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.8...v2.48.9

[2.48.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.7...v2.48.8

[2.48.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.6...v2.48.7

[2.48.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.5...v2.48.6

[2.48.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.4...v2.48.5

[2.48.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.3...v2.48.4

[2.48.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.2...v2.48.3

[2.48.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.1...v2.48.2

[2.48.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.48.0...v2.48.1

[2.48.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.32...v2.48.0

[2.47.32]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.31...v2.47.32

[2.47.31]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.30...v2.47.31

[2.47.30]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.29...v2.47.30

[2.47.29]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.28...v2.47.29

[2.47.28]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.27...v2.47.28

[2.47.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.26...v2.47.27

[2.47.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.25...v2.47.26

[2.47.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.24...v2.47.25

[2.47.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.23...v2.47.24

[2.47.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.22...v2.47.23

[2.47.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.21...v2.47.22

[2.47.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.20...v2.47.21

[2.47.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.19...v2.47.20

[2.47.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.18...v2.47.19

[2.47.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.17...v2.47.18

[2.47.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.16...v2.47.17

[2.47.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.15...v2.47.16

[2.47.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.14...v2.47.15

[2.47.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.13...v2.47.14

[2.47.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.12...v2.47.13

[2.47.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.11...v2.47.12

[2.47.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.10...v2.47.11

[2.47.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.9...v2.47.10

[2.47.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.8...v2.47.9

[2.47.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.7...v2.47.8

[2.47.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.6...v2.47.7

[2.47.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.5...v2.47.6

[2.47.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.4...v2.47.5

[2.47.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.3...v2.47.4

[2.47.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.2...v2.47.3

[2.47.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.1...v2.47.2

[2.47.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.47.0...v2.47.1

[2.47.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.20...v2.47.0

[2.46.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.19...v2.46.20

[2.46.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.18...v2.46.19

[2.46.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.17...v2.46.18

[2.46.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.16...v2.46.17

[2.46.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.15...v2.46.16

[2.46.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.14...v2.46.15

[2.46.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.13...v2.46.14

[2.46.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.12...v2.46.13

[2.46.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.11...v2.46.12

[2.46.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.10...v2.46.11

[2.46.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.9...v2.46.10

[2.46.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.8...v2.46.9

[2.46.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.7...v2.46.8

[2.46.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.6...v2.46.7

[2.46.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.5...v2.46.6

[2.46.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.4...v2.46.5

[2.46.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.3...v2.46.4

[2.46.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.2...v2.46.3

[2.46.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.1...v2.46.2

[2.46.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.46.0...v2.46.1

[2.46.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.15...v2.46.0

[2.45.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.14...v2.45.15

[2.45.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.13...v2.45.14

[2.45.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.12...v2.45.13

[2.45.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.11...v2.45.12

[2.45.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.10...v2.45.11

[2.45.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.9...v2.45.10

[2.45.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.8...v2.45.9

[2.45.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.7...v2.45.8

[2.45.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.6...v2.45.7

[2.45.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.5...v2.45.6

[2.45.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.4...v2.45.5

[2.45.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.3...v2.45.4

[2.45.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.2...v2.45.3

[2.45.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.1...v2.45.2

[2.45.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.45.0...v2.45.1

[2.45.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.72...v2.45.0

[2.44.72]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.71...v2.44.72

[2.44.71]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.70...v2.44.71

[2.44.70]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.69...v2.44.70

[2.44.69]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.68...v2.44.69

[2.44.68]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.67...v2.44.68

[2.44.67]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.66...v2.44.67

[2.44.66]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.65...v2.44.66

[2.44.65]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.64...v2.44.65

[2.44.64]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.63...v2.44.64

[2.44.63]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.62...v2.44.63

[2.44.62]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.61...v2.44.62

[2.44.61]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.60...v2.44.61

[2.44.60]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.59...v2.44.60

[2.44.59]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.58...v2.44.59

[2.44.58]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.57...v2.44.58

[2.44.57]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.56...v2.44.57

[2.44.56]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.55...v2.44.56

[2.44.55]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.54...v2.44.55

[2.44.54]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.53...v2.44.54

[2.44.53]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.52...v2.44.53

[2.44.52]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.51...v2.44.52

[2.44.51]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.50...v2.44.51

[2.44.50]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.49...v2.44.50

[2.44.49]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.48...v2.44.49

[2.44.48]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.47...v2.44.48

[2.44.47]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.46...v2.44.47

[2.44.46]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.45...v2.44.46

[2.44.45]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.44...v2.44.45

[2.44.44]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.43...v2.44.44

[2.44.43]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.42...v2.44.43

[2.44.42]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.41...v2.44.42

[2.44.41]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.40...v2.44.41

[2.44.40]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.39...v2.44.40

[2.44.39]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.38...v2.44.39

[2.44.38]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.37...v2.44.38

[2.44.37]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.36...v2.44.37

[2.44.36]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.35...v2.44.36

[2.44.35]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.34...v2.44.35

[2.44.34]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.33...v2.44.34

[2.44.33]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.32...v2.44.33

[2.44.32]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.31...v2.44.32

[2.44.31]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.30...v2.44.31

[2.44.30]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.29...v2.44.30

[2.44.29]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.28...v2.44.29

[2.44.28]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.27...v2.44.28

[2.44.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.26...v2.44.27

[2.44.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.25...v2.44.26

[2.44.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.24...v2.44.25

[2.44.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.23...v2.44.24

[2.44.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.22...v2.44.23

[2.44.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.21...v2.44.22

[2.44.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.20...v2.44.21

[2.44.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.19...v2.44.20

[2.44.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.18...v2.44.19

[2.44.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.17...v2.44.18

[2.44.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.16...v2.44.17

[2.44.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.15...v2.44.16

[2.44.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.14...v2.44.15

[2.44.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.13...v2.44.14

[2.44.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.12...v2.44.13

[2.44.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.11...v2.44.12

[2.44.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.10...v2.44.11

[2.44.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.9...v2.44.10

[2.44.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.8...v2.44.9

[2.44.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.7...v2.44.8

[2.44.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.6...v2.44.7

[2.44.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.5...v2.44.6

[2.44.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.4...v2.44.5

[2.44.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.3...v2.44.4

[2.44.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.2...v2.44.3

[2.44.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.1...v2.44.2

[2.44.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.44.0...v2.44.1

[2.44.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.7...v2.44.0

[2.43.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.6...v2.43.7

[2.43.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.5...v2.43.6

[2.43.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.4...v2.43.5

[2.43.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.3...v2.43.4

[2.43.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.2...v2.43.3

[2.43.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.1...v2.43.2

[2.43.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.43.0...v2.43.1

[2.43.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.42...v2.43.0

[2.42.42]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.41...v2.42.42

[2.42.41]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.40...v2.42.41

[2.42.40]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.39...v2.42.40

[2.42.39]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.38...v2.42.39

[2.42.38]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.37...v2.42.38

[2.42.37]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.36...v2.42.37

[2.42.36]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.35...v2.42.36

[2.42.35]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.34...v2.42.35

[2.42.34]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.33...v2.42.34

[2.42.33]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.32...v2.42.33

[2.42.32]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.31...v2.42.32

[2.42.31]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.30...v2.42.31

[2.42.30]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.29...v2.42.30

[2.42.29]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.28...v2.42.29

[2.42.28]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.27...v2.42.28

[2.42.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.26...v2.42.27

[2.42.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.25...v2.42.26

[2.42.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.24...v2.42.25

[2.42.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.23...v2.42.24

[2.42.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.22...v2.42.23

[2.42.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.21...v2.42.22

[2.42.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.20...v2.42.21

[2.42.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.19...v2.42.20

[2.42.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.18...v2.42.19

[2.42.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.17...v2.42.18

[2.42.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.16...v2.42.17

[2.42.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.15...v2.42.16

[2.42.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.14...v2.42.15

[2.42.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.13...v2.42.14

[2.42.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.12...v2.42.13

[2.42.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.11...v2.42.12

[2.42.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.10...v2.42.11

[2.42.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.9...v2.42.10

[2.42.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.8...v2.42.9

[2.42.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.7...v2.42.8

[2.42.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.6...v2.42.7

[2.42.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.5...v2.42.6

[2.42.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.4...v2.42.5

[2.42.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.3...v2.42.4

[2.42.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.2...v2.42.3

[2.42.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.1...v2.42.2

[2.42.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.42.0...v2.42.1

[2.42.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.18...v2.42.0

[2.41.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.17...v2.41.18

[2.41.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.16...v2.41.17

[2.41.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.15...v2.41.16

[2.41.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.14...v2.41.15

[2.41.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.13...v2.41.14

[2.41.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.12...v2.41.13

[2.41.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.11...v2.41.12

[2.41.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.10...v2.41.11

[2.41.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.9...v2.41.10

[2.41.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.8...v2.41.9

[2.41.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.7...v2.41.8

[2.41.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.6...v2.41.7

[2.41.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.5...v2.41.6

[2.41.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.4...v2.41.5

[2.41.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.3...v2.41.4

[2.41.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.2...v2.41.3

[2.41.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.1...v2.41.2

[2.41.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.41.0...v2.41.1

[2.41.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.40.2...v2.41.0

[2.40.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.40.1...v2.40.2

[2.40.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.40.0...v2.40.1

[2.40.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.39.2...v2.40.0

[2.39.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.39.1...v2.39.2

[2.39.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.39.0...v2.39.1

[2.39.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.7...v2.39.0

[2.38.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.6...v2.38.7

[2.38.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.5...v2.38.6

[2.38.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.4...v2.38.5

[2.38.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.3...v2.38.4

[2.38.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.2...v2.38.3

[2.38.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.1...v2.38.2

[2.38.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.38.0...v2.38.1

[2.38.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.37.0...v2.38.0

[2.37.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.36.0...v2.37.0

[2.36.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.35.0...v2.36.0

[2.35.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.34.3...v2.35.0

[2.34.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.34.2...v2.34.3

[2.34.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.34.1...v2.34.2

[2.34.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.34.0...v2.34.1

[2.34.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.36...v2.34.0

[2.33.36]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.35...v2.33.36

[2.33.35]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.34...v2.33.35

[2.33.34]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.33...v2.33.34

[2.33.33]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.32...v2.33.33

[2.33.32]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.31...v2.33.32

[2.33.31]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.30...v2.33.31

[2.33.30]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.29...v2.33.30

[2.33.29]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.28...v2.33.29

[2.33.28]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.27...v2.33.28

[2.33.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.26...v2.33.27

[2.33.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.25...v2.33.26

[2.33.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.24...v2.33.25

[2.33.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.23...v2.33.24

[2.33.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.22...v2.33.23

[2.33.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.21...v2.33.22

[2.33.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.20...v2.33.21

[2.33.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.19...v2.33.20

[2.33.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.18...v2.33.19

[2.33.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.17...v2.33.18

[2.33.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.16...v2.33.17

[2.33.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.15...v2.33.16

[2.33.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.14...v2.33.15

[2.33.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.13...v2.33.14

[2.33.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.12...v2.33.13

[2.33.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.11...v2.33.12

[2.33.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.10...v2.33.11

[2.33.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.9...v2.33.10

[2.33.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.8...v2.33.9

[2.33.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.7...v2.33.8

[2.33.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.6...v2.33.7

[2.33.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.5...v2.33.6

[2.33.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.4...v2.33.5

[2.33.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.3...v2.33.4

[2.33.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.2...v2.33.3

[2.33.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.1...v2.33.2

[2.33.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.33.0...v2.33.1

[2.33.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.20...v2.33.0

[2.32.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.19...v2.32.20

[2.32.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.18...v2.32.19

[2.32.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.17...v2.32.18

[2.32.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.16...v2.32.17

[2.32.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.15...v2.32.16

[2.32.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.14...v2.32.15

[2.32.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.13...v2.32.14

[2.32.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.12...v2.32.13

[2.32.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.11...v2.32.12

[2.32.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.10...v2.32.11

[2.32.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.9...v2.32.10

[2.32.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.8...v2.32.9

[2.32.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.7...v2.32.8

[2.32.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.6...v2.32.7

[2.32.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.5...v2.32.6

[2.32.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.4...v2.32.5

[2.32.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.3...v2.32.4

[2.32.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.2...v2.32.3

[2.32.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.1...v2.32.2

[2.32.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.32.0...v2.32.1

[2.32.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.31.3...v2.32.0

[2.31.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.31.2...v2.31.3

[2.31.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.31.1...v2.31.2

[2.31.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.31.0...v2.31.1

[2.31.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.30.0...v2.31.0

[2.30.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.8...v2.30.0

[2.29.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.7...v2.29.8

[2.29.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.6...v2.29.7

[2.29.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.5...v2.29.6

[2.29.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.4...v2.29.5

[2.29.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.3...v2.29.4

[2.29.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.2...v2.29.3

[2.29.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.1...v2.29.2

[2.29.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.29.0...v2.29.1

[2.29.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.16...v2.29.0

[2.28.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.15...v2.28.16

[2.28.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.14...v2.28.15

[2.28.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.13...v2.28.14

[2.28.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.12...v2.28.13

[2.28.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.11...v2.28.12

[2.28.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.10...v2.28.11

[2.28.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.9...v2.28.10

[2.28.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.8...v2.28.9

[2.28.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.7...v2.28.8

[2.28.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.6...v2.28.7

[2.28.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.5...v2.28.6

[2.28.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.4...v2.28.5

[2.28.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.3...v2.28.4

[2.28.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.2...v2.28.3

[2.28.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.1...v2.28.2

[2.28.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.28.0...v2.28.1

[2.28.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.15...v2.28.0

[2.27.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.14...v2.27.15

[2.27.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.13...v2.27.14

[2.27.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.12...v2.27.13

[2.27.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.11...v2.27.12

[2.27.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.10...v2.27.11

[2.27.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.9...v2.27.10

[2.27.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.8...v2.27.9

[2.27.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.7...v2.27.8

[2.27.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.6...v2.27.7

[2.27.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.5...v2.27.6

[2.27.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.4...v2.27.5

[2.27.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.3...v2.27.4

[2.27.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.2...v2.27.3

[2.27.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.1...v2.27.2

[2.27.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.27.0...v2.27.1

[2.27.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.20...v2.27.0

[2.26.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.19...v2.26.20

[2.26.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.18...v2.26.19

[2.26.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.17...v2.26.18

[2.26.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.16...v2.26.17

[2.26.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.15...v2.26.16

[2.26.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.14...v2.26.15

[2.26.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.13...v2.26.14

[2.26.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.12...v2.26.13

[2.26.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.11...v2.26.12

[2.26.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.10...v2.26.11

[2.26.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.9...v2.26.10

[2.26.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.8...v2.26.9

[2.26.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.7...v2.26.8

[2.26.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.6...v2.26.7

[2.26.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.5...v2.26.6

[2.26.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.4...v2.26.5

[2.26.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.3...v2.26.4

[2.26.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.2...v2.26.3

[2.26.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.1...v2.26.2

[2.26.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.26.0...v2.26.1

[2.26.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.11...v2.26.0

[2.25.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.10...v2.25.11

[2.25.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.9...v2.25.10

[2.25.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.8...v2.25.9

[2.25.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.7...v2.25.8

[2.25.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.6...v2.25.7

[2.25.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.5...v2.25.6

[2.25.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.4...v2.25.5

[2.25.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.3...v2.25.4

[2.25.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.2...v2.25.3

[2.25.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.1...v2.25.2

[2.25.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.25.0...v2.25.1

[2.25.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.24.4...v2.25.0

[2.24.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.24.3...v2.24.4

[2.24.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.24.2...v2.24.3

[2.24.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.24.1...v2.24.2

[2.24.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.24.0...v2.24.1

[2.24.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.9...v2.24.0

[2.23.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.8...v2.23.9

[2.23.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.7...v2.23.8

[2.23.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.6...v2.23.7

[2.23.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.5...v2.23.6

[2.23.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.4...v2.23.5

[2.23.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.3...v2.23.4

[2.23.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.2...v2.23.3

[2.23.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.1...v2.23.2

[2.23.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.23.0...v2.23.1

[2.23.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.10...v2.23.0

[2.22.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.9...v2.22.10

[2.22.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.8...v2.22.9

[2.22.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.7...v2.22.8

[2.22.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.6...v2.22.7

[2.22.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.5...v2.22.6

[2.22.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.4...v2.22.5

[2.22.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.3...v2.22.4

[2.22.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.2...v2.22.3

[2.22.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.1...v2.22.2

[2.22.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.22.0...v2.22.1

[2.22.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.27...v2.22.0

[2.21.27]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.26...v2.21.27

[2.21.26]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.25...v2.21.26

[2.21.25]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.24...v2.21.25

[2.21.24]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.23...v2.21.24

[2.21.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.22...v2.21.23

[2.21.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.21...v2.21.22

[2.21.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.20...v2.21.21

[2.21.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.19...v2.21.20

[2.21.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.18...v2.21.19

[2.21.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.17...v2.21.18

[2.21.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.16...v2.21.17

[2.21.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.15...v2.21.16

[2.21.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.14...v2.21.15

[2.21.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.13...v2.21.14

[2.21.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.12...v2.21.13

[2.21.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.11...v2.21.12

[2.21.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.10...v2.21.11

[2.21.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.9...v2.21.10

[2.21.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.8...v2.21.9

[2.21.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.7...v2.21.8

[2.21.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.6...v2.21.7

[2.21.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.5...v2.21.6

[2.21.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.4...v2.21.5

[2.21.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.3...v2.21.4

[2.21.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.2...v2.21.3

[2.21.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.1...v2.21.2

[2.21.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.21.0...v2.21.1

[2.21.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.17...v2.21.0

[2.20.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.16...v2.20.17

[2.20.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.15...v2.20.16

[2.20.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.14...v2.20.15

[2.20.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.13...v2.20.14

[2.20.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.12...v2.20.13

[2.20.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.11...v2.20.12

[2.20.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.10...v2.20.11

[2.20.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.9...v2.20.10

[2.20.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.8...v2.20.9

[2.20.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.7...v2.20.8

[2.20.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.6...v2.20.7

[2.20.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.5...v2.20.6

[2.20.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.4...v2.20.5

[2.20.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.3...v2.20.4

[2.20.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.2...v2.20.3

[2.20.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.1...v2.20.2

[2.20.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.20.0...v2.20.1

[2.20.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.19.4...v2.20.0

[2.19.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.19.3...v2.19.4

[2.19.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.19.2...v2.19.3

[2.19.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.19.1...v2.19.2

[2.19.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.19.0...v2.19.1

[2.19.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.17...v2.19.0

[2.18.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.16...v2.18.17

[2.18.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.15...v2.18.16

[2.18.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.14...v2.18.15

[2.18.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.13...v2.18.14

[2.18.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.12...v2.18.13

[2.18.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.11...v2.18.12

[2.18.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.10...v2.18.11

[2.18.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.9...v2.18.10

[2.18.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.8...v2.18.9

[2.18.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.7...v2.18.8

[2.18.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.6...v2.18.7

[2.18.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.5...v2.18.6

[2.18.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.4...v2.18.5

[2.18.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.3...v2.18.4

[2.18.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.2...v2.18.3

[2.18.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.1...v2.18.2

[2.18.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.18.0...v2.18.1

[2.18.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.8...v2.18.0

[2.17.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.7...v2.17.8

[2.17.7]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.6...v2.17.7

[2.17.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.5...v2.17.6

[2.17.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.4...v2.17.5

[2.17.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.3...v2.17.4

[2.17.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.2...v2.17.3

[2.17.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.1...v2.17.2

[2.17.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.17.0...v2.17.1

[2.17.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.5...v2.17.0

[2.16.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.4...v2.16.5

[2.16.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.3...v2.16.4

[2.16.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.2...v2.16.3

[2.16.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.1...v2.16.2

[2.16.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.16.0...v2.16.1

[2.16.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.6...v2.16.0

[2.15.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.5...v2.15.6

[2.15.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.4...v2.15.5

[2.15.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.3...v2.15.4

[2.15.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.2...v2.15.3

[2.15.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.1...v2.15.2

[2.15.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.15.0...v2.15.1

[2.15.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.14.3...v2.15.0

[2.14.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.14.2...v2.14.3

[2.14.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.14.1...v2.14.2

[2.14.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.14.0...v2.14.1

[2.14.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.6...v2.14.0

[2.13.6]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.5...v2.13.6

[2.13.5]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.4...v2.13.5

[2.13.4]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.3...v2.13.4

[2.13.3]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.2...v2.13.3

[2.13.2]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.1...v2.13.2

[2.13.1]:
https://redirect.github.com/taiki-e/install-action/compare/v2.13.0...v2.13.1

[2.13.0]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.23...v2.13.0

[2.12.23]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.22...v2.12.23

[2.12.22]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.21...v2.12.22

[2.12.21]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.20...v2.12.21

[2.12.20]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.19...v2.12.20

[2.12.19]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.18...v2.12.19

[2.12.18]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.17...v2.12.18

[2.12.17]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.16...v2.12.17

[2.12.16]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.15...v2.12.16

[2.12.15]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.14...v2.12.15

[2.12.14]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.13...v2.12.14

[2.12.13]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.12...v2.12.13

[2.12.12]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.11...v2.12.12

[2.12.11]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.10...v2.12.11

[2.12.10]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.9...v2.12.10

[2.12.9]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.8...v2.12.9

[2.12.8]:
https://redirect.github.com/taiki-e/install-action/compare/v2.12.7...v2.12.8

[2.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 07:50:10 -05:00
renovate[bot]
ecbe32a4b5
Update astral-sh/setup-uv action to v6.4.3 (#14924)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [astral-sh/setup-uv](https://redirect.github.com/astral-sh/setup-uv) |
action | patch | `v6.4.1` -> `v6.4.3` |

---

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

---

### Release Notes

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

###
[`v6.4.3`](https://redirect.github.com/astral-sh/setup-uv/releases/tag/v6.4.3):
🌈 fix relative paths starting with dots

[Compare
Source](https://redirect.github.com/astral-sh/setup-uv/compare/v6.4.2...v6.4.3)

#### 🐛 Bug fixes

- fix relative paths starting with dots
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;500](https://redirect.github.com/astral-sh/setup-uv/issues/500))

###
[`v6.4.2`](https://redirect.github.com/astral-sh/setup-uv/releases/tag/v6.4.2):
🌈 Interpret relative inputs as under working-directory

[Compare
Source](https://redirect.github.com/astral-sh/setup-uv/compare/v6.4.1...v6.4.2)

#### Changes

This release will interpret relative paths in inputs as relative
to the value of `working-directory` (default is `${{ github.workspace
}}`) .
This means the following configuration

```yaml
- uses: astral-sh/setup-uv@v6
   with:
     working-directory: /my/path
     cache-dependency-glob: uv.lock
```

will look for the `cache-dependency-glob` under `/my/path/uv.lock`

#### 🐛 Bug fixes

- interpret relative inputs as under working-directory
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;498](https://redirect.github.com/astral-sh/setup-uv/issues/498))

#### 🧰 Maintenance

- chore: update known versions for 0.8.1/0.8.2
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;497](https://redirect.github.com/astral-sh/setup-uv/issues/497))
- chore: update known versions for 0.8.0
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;491](https://redirect.github.com/astral-sh/setup-uv/issues/491))

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS40MC4wIiwidXBkYXRlZEluVmVyIjoiNDEuNDAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 12:44:37 +00:00
konsti
8cb36d6f40
Move all retry tests to network.rs (#14935)
Retry behavior isn't tied to a specific installation method, but
underlies all of them.
2025-07-28 07:33:54 -05:00
Charlie Marsh
0a51489ec4
Remove resolved TODO in allowed_indexes (#14912)
Some checks failed
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 | pyston (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
## Summary

This got solved in #14858.
2025-07-26 04:04:28 +00:00
Zanie Blue
ae1964935f
Remove extra newline (#14907)
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 | conda3.8 on linux x86-64 (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.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
Fixes https://github.com/astral-sh/uv/pull/14905#discussion_r2231915714
2025-07-25 20:40:09 +00:00
Zanie Blue
7b8dd5cfaf
Run cargo update (#14899) 2025-07-25 15:19:38 -05:00
Zanie Blue
396e198081
Update documentation for preview flags (#14902)
Follows #14823
2025-07-25 15:19:24 -05:00
Zanie Blue
c489fcb633
Update validation for enviroments and required-environments in uv.toml (#14905)
See https://github.com/astral-sh/uv/pull/14322/files#r2231891679

Closes https://github.com/astral-sh/uv/issues/14904
2025-07-25 15:19:07 -05:00
Zanie Blue
a701d3c447
Use workspace dependencies for crate dev-dependencies (#14903) 2025-07-25 13:57:49 -05:00
Zanie Blue
7f91c49701
Bump dirs to 6.0.0 to update windows-sys versions (#14898)
See https://codeberg.org/dirs/dirs-rs#6
2025-07-25 16:23:05 +00:00
Ben Beasley
8d9d929d3b
Update Rust crate console to 0.16.0 (#14890)
<!--
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? -->
This revisits https://github.com/astral-sh/uv/pull/14364, which was
opened by the renovate bot and originally failed with an error I don’t
quite understand in
https://github.com/astral-sh/uv/pull/14364#issuecomment-3017545431.

Since 852aba4f90 updated to `indicatif`
0.18, we now already have `console` 0.16 in the dependency tree. This PR
adjusts the direct dependency on `console` to match.

The only breaking change in [`console`
0.16.0](https://github.com/console-rs/console/releases/tag/0.16.0) is
that crates that depend on `console` with `default-features = False` may
need to explicitly enable the new `std` feature. This is the case for
`uv`: while I did find that `cargo test` passes with just the `console`
dependency version adjusted, this is due to [feature
unification](https://doc.rust-lang.org/cargo/reference/features.html#feature-unification),
i.e., the indirect dependency on `console` via `indicatif` 0.18 already
requires its `std` feature. We can see by inspection that `uv` should
also have a direct dependency on `console` with the `std` feature. For
example, see:


05031becc3/crates/uv-console/src/lib.rs (L1)

and note that `Term` is gated by the `std` feature in


a51fcead7c/src/lib.rs (L90-L93)

The addition of `features = ["std"]` is the key difference between this
PR and https://github.com/astral-sh/uv/pull/14364.

## Test Plan

<!-- How was it tested? -->
`cargo test`
2025-07-25 11:09:38 -05:00
Zanie Blue
bfb4bc2aeb
Split preview mode into separate feature flags (#14823)
I think this would give us better hygiene than a global flag. It makes
it easier for users to opt-in to overlapping features, such as Python
upgrades and Python bin installations and to disable warnings for
preview mode without opting in to a bunch of other features. In general,
I want to reduce the burden for putting something under preview.

The `--preview` and `--no-preview` flags are retained as global
overrides. A new `--preview-features` option is added which accepts
comma separated features or can be passed multiple times, e.g.,
`--preview-features add-bounds,pylock`. There's a `UV_PREVIEW_FEATURES`
environment variable for that option (I'm not sure if we should overload
`UV_PREVIEW`, but could be convinced).
2025-07-25 11:01:57 -05:00
konsti
9376cf5482
Remove prioritized dist duplication (#14887)
`Candidate` has an optional field `prioritized`, which was mostly
redundant with `CandidateDist`. Specifically, it was only `None`, if
`CandidateDist` was `Installed`. This commit removes this duplication.
2025-07-25 17:18:24 +02:00
Charlie Marsh
1146f3f62d
Avoid invalidating lockfile when path or workspace dependencies define explicit indexes (#14876)
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.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 / benchmarks | instrumented (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (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
## Summary

This is an alternative to #14003 that takes advantage of the fact that
we already validate that the requirements are up-to-date when validating
the lockfile, and the requirements for pinned requirements include the
index itself -- so rather than collecting all the explicit indexes
upfront, we can just add them to the available list as we iterate over
the lockfile's dependency graph.

This gets all the tests passing from that PR, but with ~no performance
impact and a much less invasive change. It also gets the "circular
dependency" test passing, which is marked with a TODO in that PR.

Closes https://github.com/astral-sh/uv/issues/11419.
2025-07-25 08:18:28 -04:00
Zanie Blue
05031becc3
Fix snapshot for GitHub message (#14881)
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 | 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 | 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.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
2025-07-24 22:40:55 +00:00
Zanie Blue
e48a9c0992
Remove redundant let Some (#14880) 2025-07-24 17:29:56 -05:00
Zanie Blue
cd4cf27d88
Add test cases for dependent conflicting extras (#14879)
Picked from #9130
2025-07-24 17:29:40 -05:00
Zanie Blue
7e78f54e7c
Bump version to 0.8.3 (#14875)
Some checks are pending
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.13 on windows x86-64 (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (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 | conda3.8 on linux x86-64 (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.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
2025-07-24 15:51:15 -05:00
Zanie Blue
23ed31b94d
Consolidate environment hash filtering (#14864)
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 | conda3.8 on linux x86-64 (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.11 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 | conda3.8 on macos aarch64 (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
2025-07-24 12:35:45 +00:00
konsti
1150de3fc5
uv_build: Allow non-standard entrypoint names (#14867)
It seems that non-standard entrypoints are still widely used,
downgrading the error to a tracing warning.

Fixes #14442

---------

Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com>
2025-07-24 14:12:36 +02:00
Elijah Hartvigsen
3b59515614
Fix typos in uv_build reference documentation (#14853)
## Summary

Fixes both typos mentioned in #14845.

## Test Plan

It wasn't :D

---------

Co-authored-by: konstin <konstin@mailbox.org>
2025-07-24 09:55:14 +00:00
Charlie Marsh
02e103f867
Respect --with versions over base environment versions (#14863)
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 | conda3.8 on linux x86-64 (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.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
## Summary

This fixes a regression from https://github.com/astral-sh/uv/pull/14447
that we seemingly didn't have test coverage for. Specifically, if you
have a version of a package in your project, and then install a
different version with `--with`, the environment should import the
`--with` version.

Closes #14860.
2025-07-24 02:00:03 +00:00
Zanie Blue
1ddfcee9e9
Fix missed stabilization of removal of registry entry during Python uninstall (#14859)
Funny enough, I caught this via
https://github.com/astral-sh/uv/pull/14823
2025-07-23 17:44:48 -05:00
Zanie Blue
30b15361e5
Publish riscv64 wheels to PyPI (#14852)
This reverts commit 49b450109b from
https://github.com/astral-sh/uv/pull/14009 following
https://github.com/pypi/warehouse/pull/18390
2025-07-23 21:52:37 +00:00
Charlie Marsh
faa12f50ce
Respect credentials from all defined indexes (#14858)
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 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 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 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 | conda3.8 on linux x86-64 (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.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
## Summary

The core problem here is that `allowed_indexes` only includes at most
one "default" index. This is problematic for tool upgrades, since the
index in the receipt will be marked as default, but credentials will be
omitted; if credentials are then defined in a `uv.toml`, we'll never
look at those, since that will _also_ be marked as default, and we only
look at the first default.

Instead, we should consider all defined indexes in priority order.

Closes https://github.com/astral-sh/uv/issues/14806.
2025-07-23 21:23:51 +00:00
Charlie Marsh
4dd0392086
Avoid writing redacted credentials to tool receipt (#14855)
## Summary

Right now, we write index URLs to the tool receipt with redacted
credentials (i.e., a username, and `****` in lieu of a password). This
is always wrong and unusable. Instead, this PR drops them entirely.

Part of https://github.com/astral-sh/uv/issues/14806.
2025-07-23 16:01:10 -04:00
Charlie Marsh
09549c2e71
Use cache_index_credentials in uv venv (#14854) 2025-07-23 16:00:56 -04:00
konsti
f7ac6875c3
Improve concurrency safety of Python downloads into cache (#14846) 2025-07-23 11:52:39 -05:00
github-actions[bot]
310a9d3426
Sync latest Python releases (#14847)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-23 11:01:09 -05:00
Zanie Blue
788b70f0fe
Move the "Cargo" install method further down in docs (#14842)
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 | 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 | conda3.8 on linux x86-64 (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.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 | 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
Closes https://github.com/astral-sh/uv/issues/14835
2025-07-23 07:11:17 -05:00
Zanie Blue
21fadbcc13
Bump version to 0.8.2 (#14832)
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
2025-07-22 19:39:53 +00:00
Nils Koch
34cda1be44
expose tls_built_in_root_certs from reqwest client (#14816)
<!--
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

We are using UV as a library and need to set `tls_built_in_root_certs`
on the reqwest client.

This PR exposes this property in the `BaseClientBuilder` and in the
`RegistryClientBuilder`. The default is set to `false`, so this does not
change any behaviour unless you explicitly opt into it.

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

## Test Plan

<!-- How was it tested? -->
2025-07-22 14:25:33 -05:00
Zanie Blue
02cc49296b
Avoid reading files in the environment bin that are not entrypoints (#14830)
Closes https://github.com/astral-sh/uv/issues/14829

I tested this against the given Dockerfile.
2025-07-22 19:11:15 +00:00
Zanie Blue
fe17b753b3
Archive the 0.7.x changelog (#14819) 2025-07-22 14:10:15 -05:00
Zanie Blue
8289e38e8f
Add UV_INIT_BUILD_BACKEND (#14821)
Closes https://github.com/astral-sh/uv/issues/14820
2025-07-22 14:10:08 -05:00
Charlie Marsh
27ade0676f
Preserve index URL priority order when writing to pyproject.toml (#14831)
## Summary

A little nuanced, but... When you add multiple `--index` URLs on the CLI
(e.g., in `uv pip install`), we check the first-provided index, then the
second index, etc. However, when we _write_ those URLs to the
`pyproject.toml` in `uv add`, we were adding them in reverse-order. We
now add them in a way that preserves the priority order.

Closes https://github.com/astral-sh/uv/issues/14817.
2025-07-22 19:09:59 +00:00
Charlie Marsh
3d1fec2732
Add derivation chains for dependency errors (#14824)
## Summary

This PR adds derivation chain for another class of resolver failures.
For example, if we encounter a transitive URL dependency, we now tell
the user which package included it, and the full derivation chain:

```
  × Failed to resolve dependencies for `foo` (v0.1.0)
  ╰─▶ Package `flask` was included as a URL dependency. URL dependencies must be
      expressed as direct requirements or constraints. Consider adding `flask @
      9d4508e893/flask-3.1.1-py3-none-any.whl`
      to your dependencies or constraints file.
  help: `foo` (v0.1.0) was included because `baz` (v0.1.0) depends on `foo`
```

Closes #14795.
2025-07-22 15:08:33 -04:00
Zanie Blue
076677da20
Avoid removing empty directories when constructing virtual environments (#14822)
Closes https://github.com/astral-sh/uv/issues/14815

I tested this with the docker-compose reproduction. You can also see a
regression test change at
2ae4464b7e
2025-07-22 13:50:14 -05:00
Zanie Blue
f0151f3a18
Bump version to 0.8.1 (#14818) 2025-07-22 11:36:20 -05:00
Zanie Blue
7d41bdb308
Allow removal of virtual environments with missing interpreters (#14812)
Co-authored-by: konsti <konstin@mailbox.org>
2025-07-22 15:16:59 +00:00
Copilot
96b889bce3
Add hint to use uv self version when uv version cannot find a project (#14738)
When users run `uv version` in a directory without a `pyproject.toml`
file, they often intend to check uv's own version rather than a
project's version. This change adds a helpful hint to guide users to the
correct command.

**Before:**
```
❯ uv version
error: No `pyproject.toml` found in current directory or any parent directory
```

**After:**
```
❯ uv version
error: No `pyproject.toml` found in current directory or any parent directory

hint: If you meant to view uv's version, use `uv self version` instead
```

## Changes

- Modified `find_target()` function in
`crates/uv/src/commands/project/version.rs` to catch
`WorkspaceError::MissingPyprojectToml` specifically and enhance the
error message with a helpful hint
- Added import for `WorkspaceError` to access the specific error type
- Updated existing tests to expect the new hint message in error output
- Added new test case `version_get_missing_with_hint()` to verify
behavior

The hint appears consistently across all scenarios where `uv version`
fails to find a project:
- `uv version` (normal mode)
- `uv version --project .` (explicit project mode)
- `uv version --preview` (preview mode)

The change maintains all existing functionality - when a
`pyproject.toml` is found, `uv version` continues to work normally
without showing the hint.

Fixes #14730.

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-22 08:32:45 -05:00
Zanie Blue
e49d61db1f
Emit JSON output with --quiet (#14810) 2025-07-22 08:21:54 -05:00
Charlie Marsh
2677e85df9
Disallow writing symlinks outside the source distribution target directory (#12259)
## Summary

Closes #12163.

## Test Plan

Created an offending source distribution with this script:

```python
import io
import tarfile
import textwrap
import time

PKG_NAME  = "badpkg"
VERSION   = "0.1"
DIST_NAME = f"{PKG_NAME}-{VERSION}"
ARCHIVE   = f"{DIST_NAME}.tar.gz"


def _bytes(data: str) -> io.BytesIO:
    """Helper: wrap a text blob as a BytesIO for tarfile.addfile()."""
    return io.BytesIO(data.encode())


def main(out_path: str = ARCHIVE) -> None:
    now = int(time.time())

    with tarfile.open(out_path, mode="w:gz") as tar:

        def add_file(path: str, data: str, mode: int = 0o644) -> None:
            """Add a regular file whose *content* is supplied as a string."""
            buf  = _bytes(data)
            info = tarfile.TarInfo(path)
            info.size   = len(buf.getbuffer())
            info.mtime  = now
            info.mode   = mode
            tar.addfile(info, buf)

        # ── top‑level setup.py ───────────────────────────────────────────────
        setup_py = textwrap.dedent(f"""\
            from setuptools import setup, find_packages
            setup(
                name="{PKG_NAME}",
                version="{VERSION}",
                packages=find_packages(),
            )
        """)
        add_file(f"{DIST_NAME}/setup.py", setup_py)

        # ── minimal package code ─────────────────────────────────────────────
        add_file(f"{DIST_NAME}/{PKG_NAME}/__init__.py", "# placeholder\\n")

        # ── the malicious symlink ────────────────────────────────────────────
        link = tarfile.TarInfo(f"{DIST_NAME}/{PKG_NAME}/evil_link")
        link.type     = tarfile.SYMTYPE
        link.mtime    = now
        link.mode     = 0o777
        link.linkname = "../../../outside.txt"
        tar.addfile(link)

    print(f"Created {out_path}")


if __name__ == "__main__":
    main()
```

Verified that both `pip install` and `uv pip install` rejected it.

I also changed `link.linkname = "../../../outside.txt"` to
`link.linkname = "/etc/outside"`, and verified that the absolute path
was rejected too.
2025-07-22 09:20:09 -04:00
Zanie Blue
c8486da495
Update virtual environment removal to delete pyvenv.cfg last (#14808)
An alternative to https://github.com/astral-sh/uv/pull/14569

This isn't a complete solution to
https://github.com/astral-sh/uv/issues/13986, in the sense that it's
still "fatal" to `uv sync` if we fail to delete an environment, but I
think that's okay — deferring deletion is much more complicated. This at
least doesn't break users once the deletion fails. The downside is we'll
generally treat this virtual environment is valid, even if we nuked a
bunch of it.

Closes https://github.com/astral-sh/uv/issues/13986
2025-07-22 08:13:38 -05:00
Zanie Blue
8bffa693b4
Copy entry points and Jupyter data directories into ephemeral environments (#14790)
Some checks are pending
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 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 | 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 | conda3.8 on linux x86-64 (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.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 is an alternative to https://github.com/astral-sh/uv/pull/14788
which has the benefit that it addresses
https://github.com/astral-sh/uv/issues/13327 which would be an issue
even if we reverted #14447.

There are two changes here

1. We copy entry points into the ephemeral environment, and rewrite
their shebangs (or trampoline target) to ensure the ephemeral
environment is not bypassed.
2. We link `etc/jupyter` and `share/jupyter` data directories into the
ephemeral environment, this is in order to ensure the above doesn't
break Jupyter which unfortunately cannot find the `share` directory
otherwise. I'd love not to do this, as it seems brittle and we don't
have a motivating use-case beyond Jupyter. I've opened
https://github.com/jupyterlab/jupyterlab/issues/17716 upstream for
discussion, as there is a viable patch that could be made upstream to
resolve the problem. I've limited the fix to Jupyter directories so we
can remove it without breakage.

Closes https://github.com/astral-sh/uv/issues/14729
Closes https://github.com/astral-sh/uv/issues/13327
Closes https://github.com/astral-sh/uv/issues/14749

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-07-22 12:11:05 +00:00
Ping Shuijie
c1bf934721
chore: fix some minor issues in comments (#14807)
<!--
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

 fix some minor issues in comments

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

## Test Plan

<!-- How was it tested? -->

Signed-off-by: pingshuijie <pingshuijie@outlook.com>
2025-07-22 10:13:05 +00:00
Charlie Marsh
ecfa386088
Error on unknown fields in dependency-metadata (#14801)
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 | conda3.8 on linux x86-64 (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.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
## Summary

Closes https://github.com/astral-sh/uv/issues/14800.
2025-07-21 22:15:03 +00:00
Charlie Marsh
036c9bef3f
Add a borrowed Realm type (#14798)
## Summary

Allows zero-cost comparisons against URL references.
2025-07-21 21:07:35 +00:00
Charlie Marsh
a3ea1b69f2
Add support for HF_TOKEN (#14797)
## Summary

If `HF_TOKEN` is set, we'll automatically wire it up to authenticate
requests when hitting private `huggingface.co` URLs in `uv run`.

## Test Plan

An unauthenticated request:

```
> cargo run -- run https://huggingface.co/datasets/cmarsh/test/resolve/main/main.py

  File "/var/folders/nt/6gf2v7_s3k13zq_t3944rwz40000gn/T/mainYadr5M.py", line 1
    Invalid username or password.
            ^^^^^^^^
SyntaxError: invalid syntax
```

An authenticated request:

```
> HF_TOKEN=hf_... cargo run run https://huggingface.co/datasets/cmarsh/test/resolve/main/main.py

Hello from main.py!
```
2025-07-21 20:55:33 +00:00
Ali Chaudry
7a56950bab
Update setup-uv docs for Github Actions integration guide (re-order python and uv setup) (#14741)
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 | conda3.8 on linux x86-64 (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.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
I updated the Github Actions integration guide to run Github's
`setup-python` before Astral's `setup-uv`, as `setup-uv`'s
`activate-environment: true` doesn't work with the original ordering.
There is a discussion about this behavior in the `setup-uv` repo
[here](https://github.com/astral-sh/setup-uv/issues/479).

<!--
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

Update the documentation for the Github Actions integration. Caveat: I'm
unsure if there are any other reasons where the original ordering (that
is,`setup-uv` before `setup-python`) might be preferred.

## Test Plan

Tested in a private Github Actions push, as documented in the
aforementioned discussion on `setup-uv`'s repo. Confirmed that removing
`source .venv/bin/activate` and replacing it with `activate-environment:
true` now works in this ordering (but didn't work with the original
ordering where `uv` installs before Github's `python`).
2025-07-21 14:48:47 -05:00
Charlie Marsh
2c8e394f03
Create (e.g.) python3.13t executables in uv venv (#14764)
## Summary

CPython's `venv` module creates these, so we should too.

On non-Windows, we add `python3.13t`.

On Windows, we add `python3.13t.exe` and `pythonw3.13t.exe` (see:
65d2c51c10/Lib/venv/__init__.py (L362)).

Closes https://github.com/astral-sh/uv/issues/14760.
2025-07-21 16:25:50 +00:00
konsti
f3dc457d2a
Introduce a generic type for list operations (#14792)
We currently have two marker keys that a list, `extras` and
`dependency_groups`, both from PEP 751. With the variants PEP, we will
add three more. This change is broken out of the wheel variants PR to
introduce generic marker list support, plus a change to use
`ContainerOperator` in more places.
2025-07-21 18:21:46 +02:00
Charlie Marsh
d052427c37
Accept &Path when creating executable links (#14791)
## Summary

I don't see a great reason for this to take an owned value. It only
needs an owned value for error cases.
2025-07-21 11:53:28 -04:00
Charlie Marsh
80708dea6e
Use a match for Windows executables in venv (#14766)
## Summary

I found it confusing that the `else` case for `== "graalpy"` is still
necessary for the `== "pypy"` branch (i.e., that `pythonw.exe` is copied
for PyPy despite not being in the `== "pypy"` branch).

Instead, we now use a match for PyP, GraalPy, and then everything else.
2025-07-21 14:48:52 +00:00
Charlie Marsh
aafeda2253
Enforce requires-python in pylock.toml (#14787)
## Summary

Turns out we weren't validating this at install-time.
2025-07-21 14:37:14 +00:00
Copilot
d768dedff6
Remove version_get_fallback_unmanaged_json test (#14786)
The `version_get_fallback_unmanaged_json` test was failing when running
tests outside of a git checkout (e.g., from a release tarball) due to
inconsistent behavior based on git availability.

The test had conditional logic that expected different outcomes
depending on whether `git_version_info_expected()` returned true or
false:
- In git checkouts: Expected failure with "The project is marked as
unmanaged" error
- Outside git checkouts: Expected success with fallback behavior showing
version info

However, the fallback behavior was removed in version 0.8.0, making this
test obsolete. All other similar tests
(`version_get_fallback_unmanaged`,
`version_get_fallback_unmanaged_short`,
`version_get_fallback_unmanaged_strict`) consistently expect failure
when a project is marked as unmanaged, regardless of git availability.

This change removes the problematic test entirely, as suggested by
@zanieb. All remaining version tests (51 total) continue to pass.

Fixes #14785.

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-21 14:17:06 +00:00
Ibraheem Ahmed
ba1319450a
Update toml to v0.9 (#14571)
## Summary

This should give us some performance and error message improvements.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-21 08:18:16 -05:00
Charlie Marsh
b81cce9152
Support extras and dependency_groups markers on uv pip install and uv pip sync (#14755)
## Summary

We don't yet support writing these, but we can at least read them
(which, e.g., allows you to install PDM-exported `pylock.toml` files
with uv, since PDM _always_ writes a default group).

Closes #14740.
2025-07-21 12:48:47 +00:00
konsti
ab48dfd0cb
Collect contains markers in enum (#14782)
We'll add more contains markers for the wheel variants, so I want to
unify them before rebasing the variants branch on them.
2025-07-21 08:38:33 -04:00
Jo
9983273289
Use sha256 checksum from GitHub API for GraalPy releases (#14779)
## Summary

Follow #14078, use GitHub generated sha256 for GraalPy releases too.

## Test Plan

```console
uv run ./crates/uv-python/fetch-download-metadata.py
```
2025-07-21 08:35:45 -04:00
konsti
8ed86a6dcd
Remove Python 3.9.18 from .python-versions (#14784)
Python 3.9.18 is not used in the tests anymore.
2025-07-21 07:27:59 -05:00
Jo
98d6ab6632
Improve CPythonFinder._parse_download_url a bit (#14780)
Some checks are pending
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (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 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 | 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 | 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 | 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 | 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
## Summary

Rename `_parse_download_url` to `_parse_download_asset` and move the
`asset['digest']` logic into it.

## Test Plan

```console
uv run ./crates/uv-python/fetch-download-metadata.py
```
2025-07-21 12:22:45 +02:00
Zanie Blue
7c2819d1f6
Match --bounds formatting for uv_build bounds in uv init (#14731)
Closes #14724 

https://chatgpt.com/codex/tasks/task_e_687a53ba646c8331baa4140c5b2bec70

---------

Co-authored-by: konstin <konstin@mailbox.org>
2025-07-21 09:48:38 +00:00
renovate[bot]
a049ba78fc
Update uraimo/run-on-arch-action action to v3 (#14778)
Some checks are pending
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (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 / 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 rocky linux 8 (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 | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (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 | 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 / 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 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 | 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.13 (push) Blocked by required conditions
2025-07-20 21:54:44 -04:00
renovate[bot]
e0feed8f9e
Update taiki-e/install-action action to v2.56.19 (#14777) 2025-07-20 21:54:38 -04:00
renovate[bot]
abcd03bc0e
Update astral-sh/setup-uv action to v6.4.1 (#14774) 2025-07-20 21:25:01 -04:00
renovate[bot]
b6d12c1b84
Update Rust crate serde_json to v1.0.141 (#14773) 2025-07-20 21:24:56 -04:00
renovate[bot]
3a949e0e53
Update Rust crate rustix to v1.0.8 (#14772) 2025-07-20 21:24:46 -04:00
renovate[bot]
51336acd2a
Update pre-commit hook astral-sh/ruff-pre-commit to v0.12.4 (#14771) 2025-07-20 21:24:34 -04:00
renovate[bot]
2c54a4acfb
Update google-github-actions/setup-gcloud digest to 6a7c903 (#14770) 2025-07-20 21:24:28 -04:00
renovate[bot]
0951ebc55c
Update google-github-actions/auth digest to 140bb51 (#14769) 2025-07-20 21:24:22 -04:00
renovate[bot]
a4c7bcf3ca
Update aws-actions/configure-aws-credentials digest to a159d7b (#14768) 2025-07-20 21:24:09 -04:00
Charlie Marsh
0487034e91
Fix bad merge in warn_uv_toml_masked_fields (#14767)
## Summary

The branch got stale and merged without flagging that this no longer
compiles.
2025-07-20 20:28:31 -04:00
Aria Desires
a42a2846e6
Make warnings about masked [tool.uv] fields more precise (#14325)
This is the second half of #14308
2025-07-20 18:54:50 -04:00
konsti
dbe6a21486
Retry request on invalid data error (#14703)
I also improved the trace logging.

Fixes #14699
2025-07-20 22:28:34 +00:00
Charlie Marsh
5e2047b253
Implement PartialEq for OptionSet (#14765)
Closes https://github.com/astral-sh/uv/issues/14737.
2025-07-20 18:17:07 -04:00
Charlie Marsh
9923f42c2e
Fix kebab casing of README variants in build backend (#14762)
## Summary

In this context, `rename_all` only applies to the variants, not their
fields.

Closes #14761.
2025-07-20 21:38:50 +00:00
Charlie Marsh
fcf0bdd3a6
Add missing the in concept link (#14763) 2025-07-20 17:38:24 -04:00
Matt Norton
d85a300b5f
Fix typo in concepts/projects/config.md (#14759) 2025-07-20 17:27:33 -04:00
Charlie Marsh
bd4c7ff860
Move dependency group normalization into specification (#14757)
Some checks are pending
CI / integration test | pyodide on ubuntu (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 | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (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 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 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 | 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
## Summary

A refactor that I'm extracting from #14755. There should be no
functional changes, but the core idea is to postpone filling in the
default `path` for a dependency group until we make the specification.
This allows us to use the groups for the `pylock.toml` in the future, if
such a `pylock.toml` is provided.
2025-07-20 14:13:27 -04:00
Charlie Marsh
a3371867ac
Support extras and dependency_groups markers in PEP 508 grammar (#14753)
## Summary

We always evaluate these to `false` right now, but we can at least parse
them.

See: https://peps.python.org/pep-0751/#dependency-groups.
2025-07-20 14:02:22 -04:00
Charlie Marsh
2d8dda34b4
Fix comment on extra_names (#14756) 2025-07-20 17:53:36 +00:00
Zanie Blue
d0a14c72a3
Fix tests requiring patch-level Python (#14733)
Closes #14723

https://chatgpt.com/codex/tasks/task_e_687a532188d08331b4352ba0a78f8fdb
2025-07-20 11:12:01 -05:00
Charlie Marsh
9c9db9b547
Clarify which portions of requires-python behavior are consistent with pip (#14752)
See: #14711
2025-07-20 09:44:25 -04:00
Charlie Marsh
d0efe1ed9c
Apply Cache-Control overrides to response, not request headers (#14736)
Some checks failed
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 | pyston (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
## Summary

This was just an oversight on my part in the initial implementation.

Closes https://github.com/astral-sh/uv/issues/14719.

## Test Plan

With:

```toml
[project]
name = "foo"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13.2"
dependencies = [
]

[[tool.uv.index]]
url = "https://download.pytorch.org/whl/cpu"
cache-control = { api = "max-age=600" }
```

Ran `cargo run lock -vvv` and verified that the PyTorch index response
was cached (whereas it typically returns `cache-control:
no-cache,no-store,must-revalidate`).
2025-07-18 16:32:29 -04:00
konsti
574aa1ef11
Better error reporting for removing Python versions from the Windows registry (#14722)
Some checks are pending
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | linux aarch64 (push) Blocked by required conditions
CI / smoke test | macos (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 explicit (push) Blocked by required conditions
CI / integration test | aarch64 windows implicit (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 | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (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 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
See
4625800484

We didn't actual use a format string, showing the template instead. We
don't show the causes in the error report, so we format it into one
error.
2025-07-18 13:26:47 +00:00
Zanie Blue
a186fda2d2
Elide traceback when python -m uv in interrupted with Ctrl-C on Windows (#14715)
Closes https://github.com/astral-sh/uv/issues/14704
2025-07-18 08:07:36 -05:00
Zanie Blue
70875128be
Disable the Windows Registry updates during python install tests (#14718) 2025-07-18 07:49:25 -05:00
konsti
d1f4f8a358
More resilient registry removal (#14717)
With the previous order of operations, there could be warnings from race
conditions between two process A and B removing and installing Python
versions.

* A removes the files for CPython3.9.18
* B sees the key CPython3.9.18
* B sees that CPython3.9.18 has no files
* A removes the key for CPython3.9.18
* B try to removes the key for CPython3.9.18, gets and error that it's
already gone, issues a warning

We make the more resilient in two ways:

* We remove the registry key first, avoiding dangling registry keys in
the removal process
* We ignore not found errors in registry removal operations: If we try
to remove something that's already gone, that's fine.

Fixes #14714 (hopefully)
2025-07-18 12:47:56 +00:00
konsti
8f2f43c561
Add a reusable path-or-URL parser (#14712)
Reviewing #14687, I noticed that we had implemented a
`Url::from_url_or_path`-like function, but it wasn't reusable. This
change `Verbatim::from_url_or_path` so we can use it in other places
too.

The PEP 508 parser is an odd place for this, but that's where
`VerbatimUrl` and `Scheme` are already living.
2025-07-18 12:08:49 +00:00
konsti
327c2bcd8a
Use SHA256 from GitHub API for Python downloads (#14708)
We recently ran over the file limit and had to drop hash file from the
releases page in favor of bulk SHA256SUMS files
(https://github.com/astral-sh/python-build-standalone/pull/691).
Conveniently, GitHub has recently started to add a SHA256 digest to the
API. GitHub did not backfill the hashes for the old releases, so use the
API hashes for newer assets, and eventually only download SHA256SUMS for
older releases.
2025-07-18 14:03:55 +02:00
konsti
bce2ea480d
Escape requires version for built_by_uv test (#14706)
This keeps the hash stable across uv releases.

Fixes #14695
2025-07-18 12:50:04 +02:00
Charlie Marsh
e724ddc63f
Allow --config-settings-package to apply configuration settings at the package level (#14573)
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
## Summary

Closes https://github.com/astral-sh/uv/issues/14564.

Closes https://github.com/astral-sh/uv/issues/10940.
2025-07-17 21:27:54 -04:00
Zanie Blue
a6a5e65e0c
Edits to the 0.8 changelog entry (#14698) 2025-07-17 18:11:22 -05:00
Zanie Blue
0b23572941 Bump version to 0.8.0
Somehow this one was missed?
2025-07-17 17:28:16 -05:00
Geoffrey Thomas
1f887552f6
CHANGELOG: manylinux_2_28 is more like 2019 (#14696)
I must have Googled something too fast, sorry. glibc 2.28 came out
August 2018, Fedora 29 was the earliest to ship with it in October 2018,
Debian 10 shipped with it in July 2019, and CentOS 8 shipped with it in
September 2019.
2025-07-17 22:25:03 +00:00
Zanie Blue
1a339b76e8 Add release notes and bump version for 0.8.0 (#14690)
[Rendered](https://github.com/astral-sh/uv/blob/zb/release-notes/CHANGELOG.md)
2025-07-17 17:20:21 -05:00
Zanie Blue
ac35377132 Fix rendering of uv venv --clear hint in bash (#14691)
Closes https://github.com/astral-sh/uv/issues/14688
2025-07-17 17:20:21 -05:00
konsti
5b716c4e50 Add missing trailing newline to outdated error (#14689)
Unlike the other branch in match, which uses a fully formatted error, we
need to print the newline ourselves.

Before (top) and after (bottom):

<img width="1296" height="585" alt="image"
src="https://github.com/user-attachments/assets/b4122ed5-591b-4fd9-a9b7-31b1e506d8aa"
/>
2025-07-17 17:20:21 -05:00
Zanie Blue
cd40a34522 Build and install workspace members that are dependencies by default (#14663)
Regardless of the presence of a build system, as in
https://github.com/astral-sh/uv/pull/14413

---------

Co-authored-by: John Mumm <jtfmumm@gmail.com>
2025-07-17 17:20:21 -05:00
Zanie Blue
0077f2357f Stabilize addition of Python executables to the bin (#14626)
Closes https://github.com/astral-sh/uv/issues/14296

As mentioned in #14681, this does not stabilize the `--default`
behavior.
2025-07-17 17:20:21 -05:00
John Mumm
ff30f14d50 Build path sources without build systems by default (#14413)
We currently treat path sources as virtual if they do not specify a
build system, which is surprising behavior. This PR updates the behavior
to treat path sources as packages unless the path source is explicitly
marked as `package = false` or its own `tool.uv.package` is set to
`false`.

Closes #12015

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-17 17:20:21 -05:00
Zanie Blue
b98ac8c224 Validate that discovered interpreters meet the Python preference (#7934)
Closes https://github.com/astral-sh/uv/issues/5144

e.g.

```
❯ cargo run -q -- sync --python-preference only-system
Using CPython 3.12.6 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 9 packages in 14ms
Installed 8 packages in 9ms
 + anyio==4.6.0
 + certifi==2024.8.30
 + h11==0.14.0
 + httpcore==1.0.5
 + httpx==0.27.2
 + idna==3.10
 + ruff==0.6.7
 + sniffio==1.3.1

❯ cargo run -q -- sync --python-preference only-managed
Using CPython 3.12.1
Removed virtual environment at: .venv
Creating virtual environment at: .venv
Resolved 9 packages in 14ms
Installed 8 packages in 11ms
 + anyio==4.6.0
 + certifi==2024.8.30
 + h11==0.14.0
 + httpcore==1.0.5
 + httpx==0.27.2
 + idna==3.10
 + ruff==0.6.7
 + sniffio==1.3.1
```
2025-07-17 17:20:21 -05:00
John Mumm
2df06ebfbc Require uv venv --clear before removing an existing directory (#14309)
By default, `uv venv <venv-name>` currently removes the `<venv-name`>
directory if it exists. This can be surprising behavior: not everyone
expects an existing environment to be overwritten. This PR updates the
default to fail if a non-empty `<venv-name>` directory already exists
and neither `--allow-existing` nor the new `-c/--clear` option is
provided (if a TTY is detected, it prompts first). If it's not a TTY,
then uv will only warn and not fail for now — we'll make this an error
in the future. I've also added a corresponding `UV_VENV_CLEAR` env var.

I've chosen to use `--clear` instead of `--force` for this option
because it is used by the `venv` module and `virtualenv` and will be
familiar to users. I also think its meaning is clearer in this context
than `--force` (which could plausibly mean force overwrite just the
virtual environment files, which is what our current `--allow-existing`
option does).

Closes #1472.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-17 17:20:21 -05:00
Zanie Blue
25e69458b1 Stabilize addition of Python versions to the Windows registry (#14625)
Following #14614 this is non-fatal and has an opt-out so it should be
safe to stabilize.
2025-07-17 17:20:21 -05:00
konsti
3c9aea87b4 uv init: Make uv_build the default build backend (from hatchling) (#14661)
Closes https://github.com/astral-sh/uv/issues/14298

Switch the default build backend for `uv init` from `hatchling` to
`uv_build`.

This change affects the following two commands:

* `uv init --lib`
* `uv init [--app] --package`

It does not affect `uv init` or `uv init --app` without `--package`. `uv
init --build-backend <...>` also works as before.

**Before**

```
$ uv init --lib project
$ cat project/pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
    { name = "konstin", email = "konstin@mailbox.org" }
]
requires-python = ">=3.13.2"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```

**After**

```
$ uv init --lib project
$ cat project/pyproject.toml
[project]
name = "project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
authors = [
    { name = "konstin", email = "konstin@mailbox.org" }
]
requires-python = ">=3.13.2"
dependencies = []

[build-system]
requires = ["uv_build>=0.7.20,<0.8"]
build-backend = "uv_build"
```

I cleaned up some tests for consistency in the second commit.
2025-07-17 17:20:21 -05:00
Aria Desires
95c0b71f77 Remove uv version fallback (#14161)
Fixes #14157

---------

Co-authored-by: John Mumm <jtfmumm@gmail.com>
2025-07-17 17:20:21 -05:00
Aria Desires
2850dc0599 make --check outdated a non-error status 1 (#14167)
In the case of `uv sync` all we really need to do is handle the
`OutdatedEnvironment` error (precisely the error we yield only on
dry-runs when everything Works but we determine things are outdated) in
`OperationDiagnostic::report` (the post-processor on all
`operations::install` calls) because any diagnostic handled by that gets
downgraded to from status 2 to status 1 (although I don't know if that's
really intentional or a random other bug in our status handling... but I
figured it's best to highlight that other potential status code
incongruence than not rely on it 😄).

Fixes #12603

---------

Co-authored-by: John Mumm <jtfmumm@gmail.com>
2025-07-17 17:20:21 -05:00
Charlie Marsh
6df7dab2df Use an ephemeral environment for uv run --with invocations (#14447)
This PR creates separation between the `--with` environment and the
environment we actually run in, which in turn solves issues like
https://github.com/astral-sh/uv/issues/12889 whereby two invocations
share the same `--with` environment, causing them to collide by way of
sharing an overlay.

Closes https://github.com/astral-sh/uv/issues/7643.
2025-07-17 17:20:21 -05:00
Aria Desires
9cf7821741 Add missing validations for disallowed uv.toml fields (#14322)
We weren't following our usual "destructure all the options" pattern in
this function, and several "this isn't actually read from uv.toml"
fields slipped through the cracks over time since folks forgot it
existed.

Fixes part of #14308, although we could still try to make the warning in
FilesystemOptions more accurate?

You could argue this is a breaking change, but I think it ultimately
isn't really, because we were already silently ignoring these fields.
Now we properly error.
2025-07-17 17:20:21 -05:00
Zanie Blue
dbaec0537a Tear miette out of the uv venv command (#14546)
This has some changes to the user-facing output, but makes it more
consistent with the rest of uv.
2025-07-17 17:20:21 -05:00
Charlie Marsh
dff9ced40a Support conflicting editable settings across groups (#14197)
If a user specifies `-e /path/to/dir` and `/path/to/dir` in a `uv pip
install` command, we want the editable to "win" (rather than erroring
due to conflicting URLs). Unfortunately, this behavior meant that when
you requested a package as editable and non-editable in conflicting
groups, the editable version was _always_ used. This PR modifies the
requisite types to use `Option<bool>` rather than `bool` for the
`editable` field, so we can determine whether a requirement was
explicitly requested as editable, explicitly requested as non-editable,
or not specified (as in the case of `/path/to/dir` in a
`requirements.txt` file). In the latter case, we allow editables to
override the "unspecified" requirement.

If a project includes a path dependency twice, once with `editable =
true` and once without any `editable` annotation, those are now
considered conflicting URLs, and lead to an error, so I've marked this
change as breaking.

Closes https://github.com/astral-sh/uv/issues/14139.
2025-07-17 17:20:21 -05:00
Charlie Marsh
c3d7d3899c Default to --workspace when adding subdirectories (#14529)
If `--workspace` is provided, we add all paths as workspace members.

If `--no-workspace` is provided, we add all paths as direct path
dependencies.

If neither is provided, then we add any paths that are under the
workspace root as workspace members, and the rest as direct path
dependencies.

Closes #14524.
2025-07-17 17:20:21 -05:00
Charlie Marsh
e4c04af32d Bump --python-platform linux to manylinux_2_28 (#14300)
Right now, `--python-platform linux` to defaults to `manylinux_2_17`.
Defaulting to `manylinux_2_17` causes some problems for users, since it
means we can't use (e.g.) `manylinux_2_28` wheels, and end up having to
build from source.

cibuildwheel made `manylinux_2_28` their default in
https://github.com/pypa/cibuildwheel/pull/1988, and there's a lot of
discussion in https://github.com/pypa/cibuildwheel/issues/1772 and
https://github.com/pypa/cibuildwheel/issues/2047. In short, the
`manylinux_2014` image is EOL, and the vast majority of consumers now
run at least glibc 2.28 (https://mayeut.github.io/manylinux-timeline/):

![Screenshot 2025-06-26 at 7 47
23 PM](https://github.com/user-attachments/assets/2672d91b-f9eb-4442-b680-7e4cd7cade91)

Note that this only changes the _default_. Users can still compile
against `manylinux_2_17` by specifying it.
2025-07-17 17:20:21 -05:00
Zanie Blue
c8925e2541 Require --global for removal of the global Python pin (#14169)
While reviewing https://github.com/astral-sh/uv/pull/14107, @oconnor663
pointed out a bug where we allow `uv python pin --rm` to delete the
global pin without the `--global` flag. I think that shouldn't be
allowed? I'm not 100% certain though.
2025-07-17 17:20:21 -05:00
samypr100
35e2f67b5e feat(docker): set default UV_TOOL_BIN_DIR on docker images (#13391)
Closes #13057

Sets `UV_TOOL_BIN_DIR` to `/usr/local/bin` for all derived images to
allow `uv tool install` to work out of the box.

Note, when the default image user is overwritten (e.g. `USER <UID>`) by
a less privileged one, an alternative writable location would now need
to be set by downstream consumers to prevent issues, hence I'm labeling
this as a breaking change for 0.8.x release.

Relates to https://github.com/astral-sh/uv-docker-example/pull/55

Each image was tested to work with uv tool with `UV_TOOL_BIN_DIR` set to
`/usr/local/bin` with the default root user and alternative non-root
users to confirm breaking nature of the change.
2025-07-17 17:20:21 -05:00
Zanie Blue
868ecd7b3a
Add support for toggling Python bin and registry install options via env vars (#14662)
Some checks are pending
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 | amazonlinux (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 | 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 | 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
Adds environment variables for
https://github.com/astral-sh/uv/pull/14612 and
https://github.com/astral-sh/uv/pull/14614

We can't use the Clap `BoolishValueParser` here, and the reasoning is a
little hard to explain. If we used `UV_PYTHON_INSTALL_NO_BIN`, as is our
typical pattern, it'd work, but here we allow opt-in to hard errors with
`UV_PYTHON_INSTALL_BIN=1` and I don't think we should have both
`UV_PYTHON_INSTALL_BIN` and `UV_PYTHON_INSTALL_NO_BIN`.

Consequently, this pull request introduces a new `EnvironmentOptions`
abstraction which allows us to express semantics that Clap cannot —
which we probably want anyway because we have an increasing number of
environment variables we're parsing downstream, e.g., #14544 and #14369.
2025-07-17 12:33:43 -05:00
Zanie Blue
78d6d1134a
Bump version to 0.7.22 (#14685) 2025-07-17 11:27:15 -05:00
adisbladis
3884ab5715
Fix bytecode compilation debug message introduced by #14369 (#14682)
## Summary

When refactoring the addition PR I accidentally introduced a bug where
the debug message would not be output if the default value is used.

cc @zanieb
2025-07-17 13:35:25 +00:00
adisbladis
bdb8c2646a
Add UV_COMPILE_BYTECODE_TIMEOUT environment variable (#14369)
## Summary

When installing packages on _very_ slow/overloaded systems it'spossible
to trigger bytecode compilation timeouts, which tends to happen in
environments such as Qemu (especially without KVM/virtio), but also on
systems that are simply overloaded. I've seen this in my Nix builds if I
for example am compiling a Linux kernel at the same time as a few other
concurrent builds.

By making the bytecode compilation timeout adjustable you can work
around such issues. I plan to set `UV_COMPILE_BYTECODE_TIMEOUT=0` in the
[pyproject.nix
builders](https://pyproject-nix.github.io/pyproject.nix/build.html) to
make them more reliable.

- Related issues

  * https://github.com/astral-sh/uv/issues/6105

## Test Plan

Only manual testing was applied in this instance. There is no existing
automated tests for bytecode compilation timeout afaict.
2025-07-17 08:11:32 -05:00
Zanie Blue
09fc943cca
Rename msrv build job for consistency with other binary builds (#14679) 2025-07-17 07:38:12 -05:00
Geoffrey Thomas
b3df1c2401
Fix typo in #14619 (#14677) 2025-07-17 08:29:41 -04:00
Geoffrey Thomas
a8bb7be52b
windows_exception: Improve async signal safety (#14619)
Some checks are pending
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 | 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.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
It's not as bad as I feared to bypass libsys's stderr. (There's still a
lock in libsys's backtrace, which might also not be too bad to bypass.)
2025-07-17 01:39:21 +00:00
Charlie Marsh
7cdc1f62ee
Suggest uv cache clean prior to --reinstall (#14659)
Some checks are pending
CI / check system | python3.10 on windows x86-64 (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 (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
## Summary

Closes https://github.com/astral-sh/uv/issues/14479.
2025-07-16 12:02:29 -04:00
konsti
052a74c451
Fix doctests (#14658)
`cargo nextest run` doesn't run them, but `cargo insta test
--test-runner nextest` does, which surfaced those failures.
2025-07-16 16:56:32 +02:00
konsti
7fece9b90a
Remove marker from Edge (#14649)
It seems that this field is unused.
2025-07-16 09:21:22 -05:00
Zanie Blue
8b29ec0bfd
Use astral.sh instead of example.com in lock_unique_named_index (#14657)
This test flakes a lot, maybe using a different domain will help

Closes https://github.com/astral-sh/uv/issues/14542
2025-07-16 09:20:25 -05:00
Zanie Blue
1f49fbd53c
Display sys.executable names in check system jobs (#14656)
Cherry-picked from https://github.com/astral-sh/uv/pull/14652

This is useful for debugging
2025-07-16 09:17:01 -05:00
github-actions[bot]
eaff96e5dc
Sync latest Python releases (#14643)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-16 09:06:06 -05:00
Zanie Blue
1b2f212e8b
Use [PYTHON] placeholder in filtered Python names (#14640)
We should never replace with a non-placeholder, it is very confusing
when trying to understand test behavior
2025-07-16 09:05:10 -05:00
Zanie Blue
0cf5ecf841
Request arm64 Python in aarch64-windows smoke test (#14655)
The Python interpreter selected by `py` recently changed to x64 instead
of arm64.

Closes https://github.com/astral-sh/uv/pull/14652
See https://github.com/astral-sh/uv/pull/14652
2025-07-16 09:04:58 -05:00
Nathan Cain
e547527587
Add UV_LIBC to allow libc selection in multi-libc environment (#14646)
Closes #14262 

## Description

Adds `UV_LIBC` environment variable and implements check within
`Libc::from_env` as recommended here:
https://github.com/astral-sh/uv/issues/14262#issuecomment-3014600313

Gave this a few passes to make sure I follow dev practices within uv as
best I am able. Feel free to call out anything that could be improved.

## Test Plan

Planned to simply run existing test suite. Open to adding more tests
once implementation is validated due to my limited Rust experience.
2025-07-16 08:52:17 -05:00
Charlie Marsh
03de6c36e3
Warn on invalid uv.toml when provided via direct path (#14653)
## Summary

We validate the `uv.toml` when it's discovered automatically, but not
when provided via `--config-file`. The same limitations exist, though --
I think the lack of enforcement is just an oversight.

Closes https://github.com/astral-sh/uv/issues/14650.
2025-07-16 13:48:16 +00:00
Gilles Peiffer
861f7a1c42
docs: add missing backtick (#14654)
Subject is message :)
2025-07-16 13:44:29 +00:00
Zanie Blue
8d6d0678a7
Move "Conflicting dependencies" to the "Resolution" page (#14633)
Some checks are pending
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 / 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 / benchmarks | instrumented (push) Blocked by required conditions
2025-07-15 16:47:43 -05:00
Zanie Blue
863e73a841
Skip Windows Python interpreters that return a broken MSIX package code (#14636)
Currently we treat all spawn failures as fatal, because they indicate a
broken interpreter. In this case, I think we should just skip these
broken interpreters — though I don't know the root cause of why it's
broken yet.

Closes https://github.com/astral-sh/uv/issues/14637
See
1394758502
2025-07-15 16:47:35 -05:00
Zanie Blue
ab2bd0179b
Mention the revision in the lockfile versioning doc (#14634) 2025-07-15 14:35:54 -05:00
Zanie Blue
d525720266
Add uv python update-shell (#14627)
Part of #14296 

This is the same as `uv tool update-shell` but handles the case where
the Python bin directory is configured to a different path.

```
❯ UV_PYTHON_BIN_DIR=/tmp/foo cargo run -q -- python install --preview 3.13.3
Installed Python 3.13.3 in 1.75s
 + cpython-3.13.3-macos-aarch64-none
warning: `/tmp/foo` is not on your PATH. To use installed Python executables, run `export PATH="/tmp/foo:$PATH"` or `uv python update-shell`.
❯ UV_PYTHON_BIN_DIR=/tmp/foo cargo run -q -- python update-shell
Created configuration file: /Users/zb/.zshenv
Restart your shell to apply changes
❯ cat /Users/zb/.zshenv
# uv
export PATH="/tmp/foo:$PATH"
❯ UV_TOOL_BIN_DIR=/tmp/bar cargo run -q -- tool update-shell
Updated configuration file: /Users/zb/.zshenv
Restart your shell to apply changes
❯ cat /Users/zb/.zshenv
# uv
export PATH="/tmp/foo:$PATH"

# uv
export PATH="/tmp/bar:$PATH"
```
2025-07-15 13:47:02 -05:00
Zanie Blue
c226d66f35
Rename "Dependency specifiers" section to exclude PEP 508 reference (#14631) 2025-07-15 12:55:57 -05:00
Zanie Blue
d2c81e503f
Make preview Python registration on Windows non-fatal (#14614)
Same as #14612 for registration with the Windows Registry.
2025-07-15 17:29:11 +00:00
Zanie Blue
bb1e9a247c
Update preview installation of Python executables to be non-fatal (#14612)
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 | 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 | 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
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
Previously, if installation of executables into the bin directory failed
we'd with a non-zero code. However, if we make this behavior the default
we don't want it to be fatal. There's a `--bin` opt-in to _require_
successful executable installation and a `--no-bin` opt-out to silence
the warning / opt-out of installation entirely.

Part of https://github.com/astral-sh/uv/issues/14296 — we need this
before we can stabilize the behavior.

In #14614 we do the same for writing entries to the Windows registry.
2025-07-15 17:12:36 +00:00
Alex Prengère
cd0d5d4748
Fix --all-arches when paired with --only-downloads (#14629)
## Summary

On current main, and on the latest released version 0.7.21, I have:

```
$ uv python list --only-downloads --all-arches
cpython-3.14.0b4-linux-x86_64-gnu                 <download available>
cpython-3.14.0b4+freethreaded-linux-x86_64-gnu    <download available>
cpython-3.13.5-linux-x86_64-gnu                   <download available>
cpython-3.13.5+freethreaded-linux-x86_64-gnu      <download available>
cpython-3.12.11-linux-x86_64-gnu                  <download available>
cpython-3.11.13-linux-x86_64-gnu                  <download available>
cpython-3.10.18-linux-x86_64-gnu                  <download available>
cpython-3.9.23-linux-x86_64-gnu                   <download available>
cpython-3.8.20-linux-x86_64-gnu                   <download available>
pypy-3.11.13-linux-x86_64-gnu                     <download available>
pypy-3.10.16-linux-x86_64-gnu                     <download available>
pypy-3.9.19-linux-x86_64-gnu                      <download available>
pypy-3.8.16-linux-x86_64-gnu                      <download available>
graalpy-3.11.0-linux-x86_64-gnu                   <download available>
graalpy-3.10.0-linux-x86_64-gnu                   <download available>
graalpy-3.8.5-linux-x86_64-gnu                    <download available>
```

As you can see, `--all-arches` is not respected here.

## Test Plan

With the patch:

```
$ cargo run python list --only-downloads --all-arches
cpython-3.14.0b4-linux-x86_64-gnu                      <download available>
cpython-3.14.0b4+freethreaded-linux-x86_64-gnu         <download available>
cpython-3.14.0b4-linux-x86_64_v2-gnu                   <download available>
cpython-3.14.0b4+freethreaded-linux-x86_64_v2-gnu      <download available>
cpython-3.14.0b4-linux-x86_64_v3-gnu                   <download available>
cpython-3.14.0b4+freethreaded-linux-x86_64_v3-gnu      <download available>
cpython-3.14.0b4-linux-x86_64_v4-gnu                   <download available>
cpython-3.14.0b4+freethreaded-linux-x86_64_v4-gnu      <download available>
cpython-3.14.0b4-linux-aarch64-gnu                     <download available>
cpython-3.14.0b4+freethreaded-linux-aarch64-gnu        <download available>
cpython-3.14.0b4-linux-powerpc64le-gnu                 <download available>
cpython-3.14.0b4+freethreaded-linux-powerpc64le-gnu    <download available>
cpython-3.14.0b4-linux-riscv64gc-gnu                   <download available>
cpython-3.14.0b4+freethreaded-linux-riscv64gc-gnu      <download available>
cpython-3.14.0b4-linux-s390x-gnu                       <download available>
cpython-3.14.0b4+freethreaded-linux-s390x-gnu          <download available>
cpython-3.13.5-linux-x86_64-gnu                        <download available>
cpython-3.13.5+freethreaded-linux-x86_64-gnu           <download available>
cpython-3.13.5-linux-x86_64_v2-gnu                     <download available>
cpython-3.13.5+freethreaded-linux-x86_64_v2-gnu        <download available>
cpython-3.13.5-linux-x86_64_v3-gnu                     <download available>
cpython-3.13.5+freethreaded-linux-x86_64_v3-gnu        <download available>
cpython-3.13.5-linux-x86_64_v4-gnu                     <download available>
cpython-3.13.5+freethreaded-linux-x86_64_v4-gnu        <download available>
cpython-3.13.5-linux-aarch64-gnu                       <download available>
cpython-3.13.5+freethreaded-linux-aarch64-gnu          <download available>
cpython-3.13.5-linux-powerpc64le-gnu                   <download available>
cpython-3.13.5+freethreaded-linux-powerpc64le-gnu      <download available>
cpython-3.13.5-linux-riscv64gc-gnu                     <download available>
cpython-3.13.5+freethreaded-linux-riscv64gc-gnu        <download available>
cpython-3.13.5-linux-s390x-gnu                         <download available>
cpython-3.13.5+freethreaded-linux-s390x-gnu            <download available>
cpython-3.12.11-linux-x86_64-gnu                       <download available>
cpython-3.12.11-linux-x86_64_v2-gnu                    <download available>
cpython-3.12.11-linux-x86_64_v3-gnu                    <download available>
cpython-3.12.11-linux-x86_64_v4-gnu                    <download available>
cpython-3.12.11-linux-aarch64-gnu                      <download available>
cpython-3.12.11-linux-powerpc64le-gnu                  <download available>
cpython-3.12.11-linux-riscv64gc-gnu                    <download available>
cpython-3.12.11-linux-s390x-gnu                        <download available>
cpython-3.11.13-linux-x86_64-gnu                       <download available>
cpython-3.11.13-linux-x86_64_v2-gnu                    <download available>
cpython-3.11.13-linux-x86_64_v3-gnu                    <download available>
cpython-3.11.13-linux-x86_64_v4-gnu                    <download available>
cpython-3.11.13-linux-aarch64-gnu                      <download available>
cpython-3.11.13-linux-powerpc64le-gnu                  <download available>
cpython-3.11.13-linux-riscv64gc-gnu                    <download available>
cpython-3.11.13-linux-s390x-gnu                        <download available>
cpython-3.11.5-linux-x86-gnu                           <download available>
cpython-3.10.18-linux-x86_64-gnu                       <download available>
cpython-3.10.18-linux-x86_64_v2-gnu                    <download available>
cpython-3.10.18-linux-x86_64_v3-gnu                    <download available>
cpython-3.10.18-linux-x86_64_v4-gnu                    <download available>
cpython-3.10.18-linux-aarch64-gnu                      <download available>
cpython-3.10.18-linux-powerpc64le-gnu                  <download available>
cpython-3.10.18-linux-riscv64gc-gnu                    <download available>
cpython-3.10.18-linux-s390x-gnu                        <download available>
cpython-3.10.13-linux-x86-gnu                          <download available>
cpython-3.9.23-linux-x86_64-gnu                        <download available>
cpython-3.9.23-linux-x86_64_v2-gnu                     <download available>
cpython-3.9.23-linux-x86_64_v3-gnu                     <download available>
cpython-3.9.23-linux-x86_64_v4-gnu                     <download available>
cpython-3.9.23-linux-aarch64-gnu                       <download available>
cpython-3.9.23-linux-powerpc64le-gnu                   <download available>
cpython-3.9.23-linux-riscv64gc-gnu                     <download available>
cpython-3.9.23-linux-s390x-gnu                         <download available>
cpython-3.9.18-linux-x86-gnu                           <download available>
cpython-3.8.20-linux-x86_64-gnu                        <download available>
cpython-3.8.20-linux-aarch64-gnu                       <download available>
cpython-3.8.17-linux-x86-gnu                           <download available>
pypy-3.11.13-linux-x86_64-gnu                          <download available>
pypy-3.11.13-linux-aarch64-gnu                         <download available>
pypy-3.11.13-linux-x86-gnu                             <download available>
pypy-3.10.16-linux-x86_64-gnu                          <download available>
pypy-3.10.16-linux-aarch64-gnu                         <download available>
pypy-3.10.16-linux-x86-gnu                             <download available>
pypy-3.10.14-linux-s390x-gnu                           <download available>
pypy-3.9.19-linux-x86_64-gnu                           <download available>
pypy-3.9.19-linux-aarch64-gnu                          <download available>
pypy-3.9.19-linux-x86-gnu                              <download available>
pypy-3.9.19-linux-s390x-gnu                            <download available>
pypy-3.8.16-linux-x86_64-gnu                           <download available>
pypy-3.8.16-linux-aarch64-gnu                          <download available>
pypy-3.8.16-linux-x86-gnu                              <download available>
pypy-3.8.16-linux-s390x-gnu                            <download available>
graalpy-3.11.0-linux-x86_64-gnu                        <download available>
graalpy-3.11.0-linux-aarch64-gnu                       <download available>
graalpy-3.10.0-linux-x86_64-gnu                        <download available>
graalpy-3.10.0-linux-aarch64-gnu                       <download available>
graalpy-3.8.5-linux-x86_64-gnu                         <download available>
graalpy-3.8.5-linux-aarch64-gnu                        <download available>
```
2025-07-15 12:03:01 -05:00
Charlie Marsh
405ef66cef
Allow users to override index cache-control headers (#14620)
## Summary

You can now override the cache control headers for the Simple API, file
downloads, or both:

```toml
[[tool.uv.index]]
name = "example"
url = "https://example.com/simple"
cache-control = { api = "max-age=600", files = "max-age=365000000, immutable" }
```

Closes https://github.com/astral-sh/uv/issues/10444.
2025-07-15 10:00:04 -04:00
Geoffrey Thomas
9871bbdc79
Fix 0.7.21 changelog (#14615)
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
2025-07-14 15:29:02 -05:00
InSync
b046e7f3be
Add missing comma in projects/dependencies.md (#14613)
## Summary

Diff:

```diff
 [dependency-groups]
 dev = [
-  {include-group = "lint"}
+  {include-group = "lint"},
   {include-group = "test"}
 ]
```

## Test Plan

None.
2025-07-14 14:06:05 -05:00
Geoffrey Thomas
77c771c7f3
Bump version to 0.7.21 (#14611) 2025-07-14 14:01:28 -04:00
Ivan Smirnov
4d82e88863
Follow links when cache-key is a glob (#13438)
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
## Summary

There's some inconsistent behaviour in handling symlinks when
`cache-key` is a glob or a file path. This PR attempts to address that.

- When cache-key is a path,
[`Path::metadata()`](https://doc.rust-lang.org/std/path/struct.Path.html#method.metadata)
is used to check if it's a file or not. According to the docs:
> This function will traverse symbolic links to query information about
the destination file.

So, if the target file is a symlink, it will be resolved and the
metadata will be queried for the underlying file.

- When cache-key is a glob, `globwalk` is used, specifically allowing
for symlinks:

  ```rust
  .file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK)
  ```

- However, without enabling link following, `DirEntry::metadata()` will
return an equivalent of `Path::symlink_metadata()` (and not
`Path::metadata()`), which will have a file type that looks like

   ```rust
   FileType {
       is_file: false,
       is_dir: false,
       is_symlink: true,
      ..
    }
    ```

- Then, there's a check for `metadata.is_file()` which fails and
complains that the target entry "is a directory when file was expected".

- TLDR: glob cache-keys don't work with symlinks.

## Solutions

Option 1 (current PR): follow symlinks.

Option 2 (also doable): don't follow symlinks, but resolve the resulting
target entry manually in case its file type is a symlink. However, this
would be a little weird and unobvious in that we resolve files but not
directories for some reason. Also, symlinking directories is pretty
useful if you want to symlink directories of local dependencies that are
not under the project's path.

## Test Plan

This has been tested manually:

```rust
fn main() {
    for follow_links in [false, true] {
        let walker = globwalk::GlobWalkerBuilder::from_patterns(".", &["a/*"])
            .file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK)
            .follow_links(follow_links)
            .build()
            .unwrap();
        let entry = walker.into_iter().next().unwrap().unwrap();
        dbg!(&entry);
        dbg!(entry.file_type());
        dbg!(entry.path_is_symlink());
        dbg!(entry.path());
        let meta = entry.metadata().unwrap();
        dbg!(meta.is_file());
    }

    let path = std::path::PathBuf::from("./a/b");
    dbg!(path.metadata().unwrap().file_type());
    dbg!(path.symlink_metadata().unwrap().file_type());
}
```

Current behaviour (glob cache-key, don't follow links):
```
[src/main.rs:9:9] &entry = DirEntry("./a/b")
[src/main.rs:10:9] entry.file_type() = FileType {
    is_file: false,
    is_dir: false,
    is_symlink: true,
    ..
}
[src/main.rs:11:9] entry.path_is_symlink() = true
[src/main.rs:12:9] entry.path() = "./a/b"
[src/main.rs:14:9] meta.is_file() = false
```

Glob cache-key, follow links:
```
[src/main.rs:9:9] &entry = DirEntry("./a/b")
[src/main.rs:10:9] entry.file_type() = FileType {
    is_file: true,
    is_dir: false,
    is_symlink: false,
    ..
}
[src/main.rs:11:9] entry.path_is_symlink() = true
[src/main.rs:12:9] entry.path() = "./a/b"
[src/main.rs:14:9] meta.is_file() = true
```

Using `path.metadata()` for a non-glob cache key:
```
[src/main.rs:18:5] path.metadata().unwrap().file_type() = FileType {
    is_file: true,
    is_dir: false,
    is_symlink: false,
    ..
}
[src/main.rs:19:5] path.symlink_metadata().unwrap().file_type() = FileType {
    is_file: false,
    is_dir: false,
    is_symlink: true,
    ..
}
```
2025-07-14 11:35:34 -04:00
Aria Desires
34fbc06ad6
Add experimental uv sync --output-format json (#13689)
This is a continuation of the work in 

* #12405 

I have:
* moved to an architecture where the human output is derived from the
json structs to centralize more of the printing state/logic
* cleaned up some of the names/types
* added tests
* removed the restriction that this output is --dry-run only

I have not yet added package info, which was TBD in their design.

---------

Co-authored-by: x0rw <mahdi.svt5@gmail.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
Co-authored-by: John Mumm <jtfmumm@gmail.com>
2025-07-14 14:53:39 +00:00
Geoffrey Thomas
df44199ceb
Add an exception handler on Windows (#14582)
We've seen a few cases of uv.exe exiting with an exception code as its
exit status and no user-visible output (#14563 in the field, and #13812
in CI). It seems that recent versions of Windows no longer show dialog
boxes on access violations (what UNIX calls segfaults) or similar
errors. Something is probably sent to Windows Error Reporting, and we
can maybe sign up to get the crashes from Microsoft, but the user
experience of seeing uv exit with no output is poor, both for end users
and during development. While it's possible to opt out of this behavior
or set up a debugger, this isn't the default configuration. (See
https://superuser.com/q/1246626 for some pointers.)

In order to get some output on a crash, we need to install our own
default handler for unhandled exceptions (or call all our code inside a
Structured Exception Handling __try/__catch block, which is complicated
on Rust). This is the moral equivalent of a segfault handler on Windows;
the kernel creates a new stack frame and passes arguments to it with
some processor state.

This commit adds a relatively simple exception handler that leans on
Rust's own backtrace implementation and also displays some minimal
information from the exception itself. This should be enough info to
communicate that something went wrong and let us collect enough
information to attempt to debug. There are also a handful of (non-Rust)
open-source libraries for this like Breakpad and Crashpad (both from
Google) and crashrpt.

The approach here, of using SetUnhandledExceptionFilter, seems to be the
standard one taken by other such libraries. Crashpad also seems to try
to use a newer mechanism for an out-of-tree DLL to report the crash:
https://issues.chromium.org/issues/42310037
If we have serious problems with memory corruption, it might be worth
adopting some third-party library that has already implemented this
approach. (In general, the docs of other crash reporting libraries are
worth skimming to understand how these things ought to work.)

Co-authored-by: samypr100 <3933065+samypr100@users.noreply.github.com>
2025-07-14 10:42:35 -04:00
renovate[bot]
852aba4f90
Update Rust crate indicatif to 0.18.0 (#14598)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [indicatif](https://redirect.github.com/console-rs/indicatif) |
workspace.dependencies | minor | `0.17.8` -> `0.18.0` |

---

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

---

### Release Notes

<details>
<summary>console-rs/indicatif (indicatif)</summary>

###
[`v0.18.0`](https://redirect.github.com/console-rs/indicatif/releases/tag/0.18.0)

[Compare
Source](https://redirect.github.com/console-rs/indicatif/compare/0.17.12...0.18.0)

Unfortunately
[0.17.12](https://redirect.github.com/console-rs/indicatif/releases/0.17.12)
had to be yanked because the console upgrade was a semver-incompatible
change. Rerelease as 0.18.0 instead.

#### What's Changed

- Bump version to 0.18.0 by
[@&#8203;djc](https://redirect.github.com/djc) in
[https://github.com/console-rs/indicatif/pull/715](https://redirect.github.com/console-rs/indicatif/pull/715)

###
[`v0.17.12`](https://redirect.github.com/console-rs/indicatif/releases/tag/0.17.12)

[Compare
Source](https://redirect.github.com/console-rs/indicatif/compare/0.17.11...0.17.12)

#### What's Changed

- Add ProgressBar::force\_draw by
[@&#8203;jaheba](https://redirect.github.com/jaheba) in
[https://github.com/console-rs/indicatif/pull/689](https://redirect.github.com/console-rs/indicatif/pull/689)
- Use width to truncate `HumanFloatCount` values by
[@&#8203;ReagentX](https://redirect.github.com/ReagentX) in
[https://github.com/console-rs/indicatif/pull/696](https://redirect.github.com/console-rs/indicatif/pull/696)
- `ProgressStyle` enable/disable colors based on draw target by
[@&#8203;tonywu6](https://redirect.github.com/tonywu6) in
[https://github.com/console-rs/indicatif/pull/699](https://redirect.github.com/console-rs/indicatif/pull/699)
- Switch dep number\_prefix to unit\_prefix by
[@&#8203;kimono-koans](https://redirect.github.com/kimono-koans) in
[https://github.com/console-rs/indicatif/pull/709](https://redirect.github.com/console-rs/indicatif/pull/709)
- draw\_target: inline the format arg to silence clippy by
[@&#8203;chris-laplante](https://redirect.github.com/chris-laplante) in
[https://github.com/console-rs/indicatif/pull/711](https://redirect.github.com/console-rs/indicatif/pull/711)
- Upgrade to console 0.16 by
[@&#8203;djc](https://redirect.github.com/djc) in
[https://github.com/console-rs/indicatif/pull/712](https://redirect.github.com/console-rs/indicatif/pull/712)

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 16:09:06 +02:00
Zanie Blue
4890f3ef2b
Do not re-resolve with a new Python version in uv tool if it is incompatible with --python (#14606)
Closes https://github.com/astral-sh/uv/issues/14604
2025-07-14 14:07:30 +00:00
renovate[bot]
0af025eafb
Update CodSpeedHQ/action action to v3.7.0 (#14597)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [CodSpeedHQ/action](https://redirect.github.com/CodSpeedHQ/action) |
action | minor | `v3.5.0` -> `v3.7.0` |

---

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

---

### Release Notes

<details>
<summary>CodSpeedHQ/action (CodSpeedHQ/action)</summary>

###
[`v3.7.0`](https://redirect.github.com/CodSpeedHQ/action/releases/tag/v3.7.0)

[Compare
Source](https://redirect.github.com/CodSpeedHQ/action/compare/v3.6.1...v3.7.0)

#### What's Changed

##### <!-- 0 -->🚀 Features

- Add pre- and post-benchmark scripts by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add cli args for perf by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;94](https://redirect.github.com/CodSpeedHQ/runner/pull/94)

##### <!-- 1 -->🐛 Bug Fixes

- Forward environment to systemd-run cmd by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Only panic in upload for non-existing integration by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Multi-line commands in valgrind by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Symlink libpython doesn't work for statically linked python by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;89](https://redirect.github.com/CodSpeedHQ/runner/pull/89)
- Run perf with sudo; support systemd-run for non-perf walltime by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Use correct path for unwind info by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)

##### <!-- 7 -->⚙️ Internals

- Add executor tests by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;95](https://redirect.github.com/CodSpeedHQ/runner/pull/95)
- Add log to detect invalid origin url by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Upgrade to edition 2024 by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add debug logs for proc maps by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;88](https://redirect.github.com/CodSpeedHQ/runner/pull/88)
- Enhance version resolution with 'latest' support and flexible formats
by [@&#8203;art049](https://redirect.github.com/art049) in
[https://github.com/CodSpeedHQ/action/pull/132](https://redirect.github.com/CodSpeedHQ/action/pull/132)

**Full Changelog**:
https://github.com/CodSpeedHQ/action/compare/v3.6.1...v3.7.0
**Full Runner Changelog**:
https://github.com/CodSpeedHQ/runner/blob/main/CHANGELOG.md

###
[`v3.6.1`](https://redirect.github.com/CodSpeedHQ/action/releases/tag/v3.6.1)

[Compare
Source](https://redirect.github.com/CodSpeedHQ/action/compare/v3.5.0...v3.6.1)

##### What's Changed

##### <!-- 0 -->🚀 Features

- Allow setting upload url via env var for convenience by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;85](https://redirect.github.com/CodSpeedHQ/runner/pull/85)
- Send unknown cpu\_brand when it is not recognized by
[@&#8203;adriencaccia](https://redirect.github.com/adriencaccia)
- Allow only running the benchmarks, and only uploading the results by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;81](https://redirect.github.com/CodSpeedHQ/runner/pull/81)
- Install perf on setup by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add perf integration for python by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add perf integration for rust by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Add fifo ipc by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Use custom time formatting to be in line with the rest of CodSpeed by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;77](https://redirect.github.com/CodSpeedHQ/runner/pull/77)
- Output information about benches after a local run by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;76](https://redirect.github.com/CodSpeedHQ/runner/pull/76)
- Allow specifying oauth token through CLI by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;75](https://redirect.github.com/CodSpeedHQ/runner/pull/75)
- Add option to output structured json by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;74](https://redirect.github.com/CodSpeedHQ/runner/pull/74)
- Add flags to specify repository from CLI by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
- Improve error handling for valgrind by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;67](https://redirect.github.com/CodSpeedHQ/runner/pull/67)
- Handle local run failure by
[@&#8203;adriencaccia](https://redirect.github.com/adriencaccia) in
[#&#8203;71](https://redirect.github.com/CodSpeedHQ/runner/pull/71)
- Run benchmark with systemd (for optional cpu isolation) by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;86](https://redirect.github.com/CodSpeedHQ/runner/pull/86)

##### <!-- 1 -->🐛 Bug Fixes

- Persist logs when running with skip\_upload by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in [#&#8203;84](https://redirect.github.com/CodSpeedHQ/runner/pull/84)
- Valgrind crash for unresolved libpython by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;82](https://redirect.github.com/CodSpeedHQ/runner/pull/82)
- Support trailing slash in origin url by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;83](https://redirect.github.com/CodSpeedHQ/runner/pull/83)
- Use bash to ensure correct behavior across systems by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Fix test randomly failing due to other test run in parallel by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
- Check child status code after valgrind by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;72](https://redirect.github.com/CodSpeedHQ/runner/pull/72)
- Only show perf output at debug or trace level by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias) in
[#&#8203;87](https://redirect.github.com/CodSpeedHQ/runner/pull/87)

##### <!-- 7 -->⚙️ Internals

- Dont use regex in perf map harvest by
[@&#8203;not-matthias](https://redirect.github.com/not-matthias)
- Switch to astral-sh/cargo-dist by
[@&#8203;adriencaccia](https://redirect.github.com/adriencaccia) in
[#&#8203;80](https://redirect.github.com/CodSpeedHQ/runner/pull/80)

**Full Changelog**:
https://github.com/CodSpeedHQ/action/compare/v3.5.0...v3.6.1
**Full Runner Changelog**:
https://github.com/CodSpeedHQ/runner/blob/main/CHANGELOG.md

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 08:59:09 -05:00
renovate[bot]
3b050b5545
Update Rust crate tokio to v1.46.1 (#14599) 2025-07-14 09:58:55 -04:00
Zanie Blue
9efd053d27
Add test case for uv tool Python re-resolves (#14605)
A test case for https://github.com/astral-sh/uv/pull/10401 and
https://github.com/astral-sh/uv/pull/14606
2025-07-14 08:56:39 -05:00
renovate[bot]
d179c496dd
Update Rust crate spdx to v0.10.9 (#14596)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [spdx](https://redirect.github.com/EmbarkStudios/spdx) |
workspace.dependencies | patch | `0.10.8` -> `0.10.9` |

---

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

---

### Release Notes

<details>
<summary>EmbarkStudios/spdx (spdx)</summary>

###
[`v0.10.9`](https://redirect.github.com/EmbarkStudios/spdx/blob/HEAD/CHANGELOG.md#0109---2025-07-12)

[Compare
Source](https://redirect.github.com/EmbarkStudios/spdx/compare/0.10.8...0.10.9)

##### Changed

- [PR#74](https://redirect.github.com/EmbarkStudios/spdx/pull/76) update
SPDX license list to 3.27.0.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 15:49:11 +02:00
renovate[bot]
ef7ab76206
Update Rust crate codspeed-criterion-compat to v3.0.3 (#14594)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [codspeed-criterion-compat](https://codspeed.io)
([source](https://redirect.github.com/CodSpeedHQ/codspeed-rust)) |
dependencies | patch | `3.0.2` -> `3.0.3` |

---

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

---

### Release Notes

<details>
<summary>CodSpeedHQ/codspeed-rust (codspeed-criterion-compat)</summary>

###
[`v3.0.3`](https://redirect.github.com/CodSpeedHQ/codspeed-rust/releases/tag/v3.0.3)

[Compare
Source](https://redirect.github.com/CodSpeedHQ/codspeed-rust/compare/v3.0.2...v3.0.3)

#### What's Changed

- tests: cargo-bench should work with the compat layers by
[@&#8203;art049](https://redirect.github.com/art049) in
[https://github.com/CodSpeedHQ/codspeed-rust/pull/110](https://redirect.github.com/CodSpeedHQ/codspeed-rust/pull/110)
- fix: handle rustflags from .cargo/config.toml by
[@&#8203;GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in
[https://github.com/CodSpeedHQ/codspeed-rust/pull/109](https://redirect.github.com/CodSpeedHQ/codspeed-rust/pull/109)

**Full Changelog**:
https://github.com/CodSpeedHQ/codspeed-rust/compare/v3.0.2...v3.0.3

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 15:48:47 +02:00
renovate[bot]
4c40dd341e
Update Rust crate hyper-util to v0.1.15 (#14595)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [hyper-util](https://hyper.rs)
([source](https://redirect.github.com/hyperium/hyper-util)) |
dev-dependencies | patch | `0.1.14` -> `0.1.15` |

---

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

---

### Release Notes

<details>
<summary>hyperium/hyper-util (hyper-util)</summary>

###
[`v0.1.15`](https://redirect.github.com/hyperium/hyper-util/blob/HEAD/CHANGELOG.md#0115-2025-07-07)

[Compare
Source](https://redirect.github.com/hyperium/hyper-util/compare/v0.1.14...v0.1.15)

- Add header casing options to `auto::Builder`.
- Fix `proxy::Socksv5` to check for enough bytes before parsing ipv6
responses.
- Fix including `client-proxy` in the `full` feature set.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 15:45:56 +02:00
renovate[bot]
e9509fde84
Update Rust crate clap to v4.5.41 (#14593)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [clap](https://redirect.github.com/clap-rs/clap) |
workspace.dependencies | patch | `4.5.40` -> `4.5.41` |

---

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

---

### Release Notes

<details>
<summary>clap-rs/clap (clap)</summary>

###
[`v4.5.41`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4541---2025-07-09)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.40...v4.5.41)

##### Features

- Add `Styles::context` and `Styles::context_value` to customize the
styling of `[default: value]` like notes in the `--help`

</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:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuMjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 15:42:56 +02:00
renovate[bot]
a57241c0d7
Update pre-commit hook astral-sh/ruff-pre-commit to v0.12.3 (#14592)
Some checks are pending
CI / check system | x86-64 python3.13 on windows aarch64 (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 | 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 | 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 | 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
2025-07-13 21:10:28 -04:00
github-actions[bot]
4175e3eb4d
Sync latest Python releases (#14581)
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 | conda3.8 on linux x86-64 (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.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
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-13 08:20:51 -05:00
Geoffrey Thomas
7ea030a1a8
Bump Python releases to pick up python-build-standalone 20250712 (#14578)
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 | 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
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
This is primarily a regression fix for missing SQLite extensions
(astral-sh/python-build-standalone#694).
2025-07-12 12:46:40 -04:00
Zanie Blue
ee35fe34ab
Increase the number of retries during test runs in CI (#14565)
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
2025-07-11 13:59:47 -05:00
Zanie Blue
081e2010df
Isolate install_git_public_rate_limited... test from UV_HTTP_RETRIES (#14567)
Blocking https://github.com/astral-sh/uv/pull/14565

This also makes the test 5x faster, from 5s to 1s.
2025-07-11 17:13:35 +00:00
dmitry-bychkov
a9e21f7f6b
Update CONTRIBUTING.md with instructions to format markdown files (#14246)
<!--
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

Current documentation requires contributors to have Node.js/npm
installed locally to format Markdown files. This might be problematic
for users who don't work with JavaScript ecosystem or users who want to
avoid toolchain setup.

This change adds docker-based alternative:

```
docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md"
```

Which mounts current working directory into /src/ inside of a container
and also sets working directory (-w) to /src/ so prettier loads
.editorconfig.

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

## Test Plan

Both commands should produce the same output

<details>
<summary>Native Prettier</summary>

```console
➜  uv git:(docs/contributing-md-formatting) npx prettier --prose-wrap always --write "**/*.md"
.github/PULL_REQUEST_TEMPLATE.md 28ms (unchanged)
BENCHMARKS.md 30ms (unchanged)
changelogs/0.1.x.md 264ms (unchanged)
changelogs/0.2.x.md 223ms (unchanged)
changelogs/0.3.x.md 29ms (unchanged)
changelogs/0.4.x.md 126ms (unchanged)
changelogs/0.5.x.md 153ms (unchanged)
changelogs/0.6.x.md 77ms (unchanged)
CONTRIBUTING.md 9ms (unchanged)
crates/README.md 4ms (unchanged)
crates/uv-build/README.md 1ms (unchanged)
crates/uv-client/README.md 1ms (unchanged)
crates/uv-globfilter/README.md 3ms (unchanged)
crates/uv-pep440/Readme.md 6ms (unchanged)
crates/uv-pep508/Readme.md 3ms (unchanged)
crates/uv-python/python/packaging/README.md 1ms (unchanged)
crates/uv-trampoline/README.md 14ms (unchanged)
crates/uv-virtualenv/README.md 1ms (unchanged)
docs/concepts/authentication.md 10ms (unchanged)
docs/concepts/build-backend.md 11ms (unchanged)
docs/concepts/cache.md 17ms (unchanged)
docs/concepts/configuration-files.md 9ms (unchanged)
docs/concepts/index.md 2ms (unchanged)
docs/concepts/indexes.md 22ms (unchanged)
docs/concepts/projects/build.md 4ms (unchanged)
docs/concepts/projects/config.md 25ms (unchanged)
docs/concepts/projects/dependencies.md 29ms (unchanged)
docs/concepts/projects/index.md 2ms (unchanged)
docs/concepts/projects/init.md 10ms (unchanged)
docs/concepts/projects/layout.md 10ms (unchanged)
docs/concepts/projects/run.md 4ms (unchanged)
docs/concepts/projects/sync.md 11ms (unchanged)
docs/concepts/projects/workspaces.md 12ms (unchanged)
docs/concepts/python-versions.md 26ms (unchanged)
docs/concepts/resolution.md 40ms (unchanged)
docs/concepts/tools.md 19ms (unchanged)
docs/getting-started/features.md 8ms (unchanged)
docs/getting-started/first-steps.md 2ms (unchanged)
docs/getting-started/help.md 8ms (unchanged)
docs/getting-started/index.md 2ms (unchanged)
docs/getting-started/installation.md 8ms (unchanged)
docs/guides/index.md 2ms (unchanged)
docs/guides/install-python.md 31ms (unchanged)
docs/guides/integration/alternative-indexes.md 21ms (unchanged)
docs/guides/integration/aws-lambda.md 49ms (unchanged)
docs/guides/integration/dependency-bots.md 16ms (unchanged)
docs/guides/integration/docker.md 37ms (unchanged)
docs/guides/integration/fastapi.md 8ms (unchanged)
docs/guides/integration/github.md 36ms (unchanged)
docs/guides/integration/index.md 4ms (unchanged)
docs/guides/integration/jupyter.md 17ms (unchanged)
docs/guides/integration/marimo.md 11ms (unchanged)
docs/guides/integration/pre-commit.md 27ms (unchanged)
docs/guides/integration/pytorch.md 12ms (unchanged)
docs/guides/package.md 5ms (unchanged)
docs/guides/projects.md 12ms (unchanged)
docs/guides/scripts.md 19ms (unchanged)
docs/guides/tools.md 8ms (unchanged)
docs/index.md 7ms (unchanged)
docs/pip/compatibility.md 44ms (unchanged)
docs/pip/compile.md 13ms (unchanged)
docs/pip/dependencies.md 3ms (unchanged)
docs/pip/environments.md 10ms (unchanged)
docs/pip/index.md 2ms (unchanged)
docs/pip/inspection.md 1ms (unchanged)
docs/pip/packages.md 3ms (unchanged)
docs/reference/benchmarks.md 3ms (unchanged)
docs/reference/index.md 3ms (unchanged)
docs/reference/installer.md 2ms (unchanged)
docs/reference/policies/index.md 2ms (unchanged)
docs/reference/policies/license.md 2ms (unchanged)
docs/reference/policies/platforms.md 4ms (unchanged)
docs/reference/policies/versioning.md 2ms (unchanged)
docs/reference/resolver-internals.md 19ms (unchanged)
docs/reference/troubleshooting/build-failures.md 13ms (unchanged)
docs/reference/troubleshooting/index.md 1ms (unchanged)
docs/reference/troubleshooting/reproducible-examples.md 7ms (unchanged)
PIP_COMPATIBILITY.md 1ms (unchanged)
README.md 10ms (unchanged)
scripts/benchmark/README.md 1ms (unchanged)
scripts/packages/built-by-uv/README.md 1ms (unchanged)
scripts/packages/dependent_locals/first_local/README.md 0ms (unchanged)
scripts/packages/dependent_locals/second_local/README.md 0ms (unchanged)
scripts/packages/hatchling_editable/README.md 0ms (unchanged)
scripts/packages/README.md 1ms (unchanged)
scripts/packages/root_editable/README.md 0ms (unchanged)
scripts/workspaces/albatross-virtual-workspace/packages/Unrelated.md 1ms (unchanged)
SECURITY.md 2ms (unchanged)
STYLE.md 9ms (unchanged)
➜  uv git:(docs/contributing-md-formatting) git status
On branch docs/contributing-md-formatting
nothing to commit, working tree clean
➜  uv git:(docs/contributing-md-formatting)
```
</details>

<details>
<summary>Docker based</summary>

```console
➜  uv git:(docs/contributing-md-formatting) sudo docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md"
npm warn exec The following package was not found and will be installed: prettier@3.6.0
.github/PULL_REQUEST_TEMPLATE.md 54ms (unchanged)
BENCHMARKS.md 41ms (unchanged)
changelogs/0.1.x.md 297ms (unchanged)
changelogs/0.2.x.md 306ms (unchanged)
changelogs/0.3.x.md 50ms (unchanged)
changelogs/0.4.x.md 137ms (unchanged)
changelogs/0.5.x.md 217ms (unchanged)
changelogs/0.6.x.md 114ms (unchanged)
CONTRIBUTING.md 12ms (unchanged)
crates/README.md 8ms (unchanged)
crates/uv-build/README.md 2ms (unchanged)
crates/uv-client/README.md 2ms (unchanged)
crates/uv-globfilter/README.md 6ms (unchanged)
crates/uv-pep440/Readme.md 8ms (unchanged)
crates/uv-pep508/Readme.md 5ms (unchanged)
crates/uv-python/python/packaging/README.md 2ms (unchanged)
crates/uv-trampoline/README.md 17ms (unchanged)
crates/uv-virtualenv/README.md 2ms (unchanged)
docs/concepts/authentication.md 20ms (unchanged)
docs/concepts/build-backend.md 20ms (unchanged)
docs/concepts/cache.md 35ms (unchanged)
docs/concepts/configuration-files.md 11ms (unchanged)
docs/concepts/index.md 3ms (unchanged)
docs/concepts/indexes.md 24ms (unchanged)
docs/concepts/projects/build.md 5ms (unchanged)
docs/concepts/projects/config.md 25ms (unchanged)
docs/concepts/projects/dependencies.md 38ms (unchanged)
docs/concepts/projects/index.md 3ms (unchanged)
docs/concepts/projects/init.md 15ms (unchanged)
docs/concepts/projects/layout.md 11ms (unchanged)
docs/concepts/projects/run.md 7ms (unchanged)
docs/concepts/projects/sync.md 15ms (unchanged)
docs/concepts/projects/workspaces.md 15ms (unchanged)
docs/concepts/python-versions.md 30ms (unchanged)
docs/concepts/resolution.md 52ms (unchanged)
docs/concepts/tools.md 20ms (unchanged)
docs/getting-started/features.md 10ms (unchanged)
docs/getting-started/first-steps.md 2ms (unchanged)
docs/getting-started/help.md 5ms (unchanged)
docs/getting-started/index.md 3ms (unchanged)
docs/getting-started/installation.md 8ms (unchanged)
docs/guides/index.md 2ms (unchanged)
docs/guides/install-python.md 49ms (unchanged)
docs/guides/integration/alternative-indexes.md 29ms (unchanged)
docs/guides/integration/aws-lambda.md 102ms (unchanged)
docs/guides/integration/dependency-bots.md 20ms (unchanged)
docs/guides/integration/docker.md 38ms (unchanged)
docs/guides/integration/fastapi.md 7ms (unchanged)
docs/guides/integration/github.md 46ms (unchanged)
docs/guides/integration/index.md 3ms (unchanged)
docs/guides/integration/jupyter.md 16ms (unchanged)
docs/guides/integration/marimo.md 6ms (unchanged)
docs/guides/integration/pre-commit.md 14ms (unchanged)
docs/guides/integration/pytorch.md 18ms (unchanged)
docs/guides/package.md 9ms (unchanged)
docs/guides/projects.md 11ms (unchanged)
docs/guides/scripts.md 13ms (unchanged)
docs/guides/tools.md 13ms (unchanged)
docs/index.md 11ms (unchanged)
docs/pip/compatibility.md 40ms (unchanged)
docs/pip/compile.md 12ms (unchanged)
docs/pip/dependencies.md 4ms (unchanged)
docs/pip/environments.md 10ms (unchanged)
docs/pip/index.md 4ms (unchanged)
docs/pip/inspection.md 2ms (unchanged)
docs/pip/packages.md 5ms (unchanged)
docs/reference/benchmarks.md 2ms (unchanged)
docs/reference/index.md 3ms (unchanged)
docs/reference/installer.md 3ms (unchanged)
docs/reference/policies/index.md 1ms (unchanged)
docs/reference/policies/license.md 3ms (unchanged)
docs/reference/policies/platforms.md 5ms (unchanged)
docs/reference/policies/versioning.md 4ms (unchanged)
docs/reference/resolver-internals.md 29ms (unchanged)
docs/reference/troubleshooting/build-failures.md 19ms (unchanged)
docs/reference/troubleshooting/index.md 2ms (unchanged)
docs/reference/troubleshooting/reproducible-examples.md 9ms (unchanged)
PIP_COMPATIBILITY.md 1ms (unchanged)
README.md 15ms (unchanged)
scripts/benchmark/README.md 1ms (unchanged)
scripts/packages/built-by-uv/README.md 1ms (unchanged)
scripts/packages/dependent_locals/first_local/README.md 0ms (unchanged)
scripts/packages/dependent_locals/second_local/README.md 0ms (unchanged)
scripts/packages/hatchling_editable/README.md 1ms (unchanged)
scripts/packages/README.md 1ms (unchanged)
scripts/packages/root_editable/README.md 0ms (unchanged)
scripts/workspaces/albatross-virtual-workspace/packages/Unrelated.md 2ms (unchanged)
SECURITY.md 3ms (unchanged)
STYLE.md 16ms (unchanged)
npm notice
npm notice New minor version of npm available! 11.3.0 -> 11.4.2
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.4.2
npm notice To update run: npm install -g npm@11.4.2
npm notice
➜  uv git:(docs/contributing-md-formatting) git status
On branch docs/contributing-md-formatting
nothing to commit, working tree clean
➜  uv git:(docs/contributing-md-formatting)
```

</details>

Co-authored-by: Dmitry Bychkov <dbychkov@alarislabs.com>
2025-07-11 12:05:15 -05:00
Zanie Blue
088a436efe
Move run_to_completion utility to crate::child instead of crate::commands::run (#14566)
This was really confusing as everything else in the `commands` module is
a command
2025-07-11 16:45:45 +00:00
Ivan Smirnov
567468ce72
More efficient cache-key globbing + support parent paths in globs (#13469)
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 | python3.13 (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 | 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
## Summary

(Related PR: #13438 - would be nice to have it merged as well since it
touches on the same globwalker code)

There's a few issues with `cache-key` globs, which this PR attempts to
address:

- As of the current state, parent or absolute paths are not allowed,
which is not obvious and is not documented. E.g., cache-key paths of the
form `{file = "../dep/**"}` will be essentially ignored.
- Absolute glob patterns also don't work (funnily enough, there's logic
in `globwalk` itself that attempts to address it in
[`globwalk::glob_builder()`](8973fa2bc5/src/lib.rs (L415)),
which serves as inspiration to some parts of this PR).
- The reason for parent paths being ignored is the way globwalker is
currently being triggered in `uv-cache-info`: the base directory is
being walked over completely and each entry is then being matched to one
of the provided match patterns.
- This may also end up being very inefficient if you have a huge root
folder with thousands of files: if your match patterns are `a/b/*.rs`
and `a/c/*.py` then instead of walking over the root directory, you can
just walk over `a/b` and `a/c` and match the relevant patterns there.
- Why supporting parent paths may be important to the point of being a
blocker: in large codebases with python projects depending on other
local non-python projects (e.g. rust crates), cache-keys can be very
useful to track dependency on the source code of the latter (e.g.
`cache-keys = [{ file = "../../crates/some-dep/**" }]`.
- TLDR: parent/absolute cache-key globs don't work, glob walk can be
slow.

## Solution

- In this PR, user-provided glob patterns are first clustered
(LCP-style) into pattern groups with longest common path prefix; each of
these groups can then be walked over separately.
- Pattern groups do not overlap, so we would never walk over the same
directory twice (unless there's symlinks pointing to same folders).
- Paths are not canonicalized nor virtually normalized (which is
impossible on Unix without FS access), so the method is symlink-safe
(i.e. we don't treat `a/b/..` as `a`) and should work fine with #13438.
- Because of LCP logic, the minimal amount of directory space will be
traversed to cover all patterns.
- Absolute glob patterns will now work.
- Parent-relative glob patterns will now work.
- Glob walking will be more efficient in some cases.

## Possible improvements

- Efficiency can be further greatly improved if we limit max depth for
globwalk. Currently, a simple ".toml" will deep-traverse the whole
folder. Essentially, max depth can be always set to either N or
infinity. If a pattern at a pivot node contains `**`, we collect all
children nodes from the subtree into the same group and don't limit max
depth; otherwise, we set max depth to the length of the glob pattern.
This wouldn't change correctness though and can we done separately if
needed.
- If this is considered important enough, docs can be updated to
indicate that parent and absolute globs are supported (and symlinks are
resolved, if the relevant PR is algo merged in).

## Test Plan

- Glob splitting and clustering tests are included in the PR.
- Relative and absolute glob cache-keys were tested in an actual
codebase.
2025-07-11 10:01:54 -05:00
Zanie Blue
71470b7b1a
Add UV_HTTP_RETRIES to customize retry counts (#14544)
I want to increase this number in CI and was surprised we didn't support
configuration yet.
2025-07-11 07:35:27 -05:00
Charlie Marsh
2e0f399eeb
Run cargo dev generate-all (#14555)
Some checks are pending
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 | python on debian (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
## Summary

I think we had a missing rebase.
2025-07-11 01:46:44 +00:00
Charlie Marsh
cc5d5d5fba
Fix repeated word in Pyodide doc (#14554) 2025-07-11 01:41:32 +00:00
Charlie Marsh
0fb8c2b1d7
Add --python-platform to uv sync (#14320)
## Summary

Closes https://github.com/astral-sh/uv/issues/14273.
2025-07-11 01:38:28 +00:00
Zanie Blue
1b2ac40568
Fix if on macos test job (#14551) 2025-07-10 18:19:45 -05:00
Charlie Marsh
a3bc30c1a7
Use astral-sh fork of rs-async-zip (#14552)
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
## Summary

I transferred ownership from my personal GitHub to `astral-sh`. There's
no change in contents, etc.
2025-07-10 19:00:22 -04:00
Noam Teyssier
43dbdba578
feature: shorthand for --with (-w) in uvx and uv tool run (#14530)
<!--
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

This is a small quality of life feature that adds a shorthand (`-w`) to
the `--with` flag for minimizing keystrokes.

Pretty minor, but I didn't see any conflicts with `-w` and thought this
could be a nice place for it.

```bash
# proposed addition (short)
uvx -w numpy ipython

# original (long)
uvx --with numpy ipython
```

## Test Plan

Added testing already in the P.R. - just copied over tests from the
`--with` flag

<!-- How was it tested? -->
2025-07-10 13:50:50 -05:00
Ben Beasley
b0348ee2a9
Conditionalize version_extras test on the pypi feature (#14536)
<!--
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

The `version_extras` test added in
85c0fc963b needs to connect to PyPI. This
PR conditionalizes it on the `pypi` extra so that people running the
tests offline don’t have to skip that test explicitly.
<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

<!-- How was it tested? -->
I already ran `cargo test` in the git checkout to confirm I didn’t
somehow introduce a syntax error. I am also applying this PR as a patch
to [the `uv` package in Fedora](https://src.fedoraproject.org/rpms/uv),
which runs tests offline with the `pypi` feature disabled.
2025-07-10 13:19:36 -05:00
Zanie Blue
02345a5a7d
Add hint when Python downloads are disabled (#14522)
Follow-up to https://github.com/astral-sh/uv/pull/14509 to provide the
_reason_ downloads are disabled and surface it as a hint rather than a
debug log.

e.g.,

```
❯ cargo run -q -- run --no-managed-python -p 3.13.4 python
error: No interpreter found for Python 3.13.4 in virtual environments or search path

hint: A managed Python download is available for Python 3.13.4, but the Python preference is set to 'only system'
```
2025-07-10 12:06:24 -05:00
Zanie Blue
1dff18897a
Only run macOS tests on main without opt-in (#14541)
Some checks are pending
CI / check system | python3.12 via chocolatey (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
These runners are expensive and have limited concurrency, let's just run
them on `main`.
2025-07-10 08:53:27 -05:00
Aria Desires
042df4a7de
Expand the functionality of uv version --bump to support pre-releases (#13578)
This adds `alpha`, `beta`, `rc`, `stable`, `post`, and `dev` modes to
`uv version --bump`.

The components that `--bump` accepts are ordered as follows:

    major > minor > patch > stable > alpha > beta > rc > post > dev
    
Bumping a component "clears" all lesser component (`alpha`, `beta`, and
`rc` all overwrite each other):

* `--bump minor` on `1.2.3a4.post5.dev6` => `1.3.0`
* `--bump alpha` on `1.2.3a4.post5.dev6` => `1.2.3a5` 
* `--bump dev  ` on `1.2.3a4.post5.dev6` => `1.2.3a4.post5.dev7`

In addition, `--bump` can now be repeated. The primary motivation of
this is "bump stable version and also enter a prerelease", but it
technically lets you express other things if you want them:

* `--bump patch --bump alpha` on `1.2.3` => `1.2.4a1` ("bump patch
version and go to alpha 1")
* `--bump minor --bump patch` on `1.2.3` => `1.3.1` ("bump minor version
and got to patch 1")
* `--bump minor --bump minor` on `1.2.3` => `1.4.0` ("bump minor version
twice")

The `--bump` flags are sorted by their priority, so that you don't need
to remember the priority yourself. This ordering is the only "useful"
one that preserves every `--bump` you passed, so there's no concern
about loss of expressiveness. For instance `--bump minor --bump major`
would just be `--bump major` if we didn't sort, as the major bump clears
the minor version. The ordering of `beta` after `alpha` means `--bump
alpha --bump beta` will just result in beta 1; this is the one case
where a bump request will effectively get overwritten.

The `stable` mode "bumps to the next stable release", clearing the pre
(`alpha`, `beta`, `rc`), `dev`, and `post` components from a version
(`1.2.3a4.post5.dev6` => `1.2.3`). The choice to clear `post` here is a
bit odd, in that `1.2.3.post4` => `1.2.3` is actually a version
decrease, but I think this gives a more intuitive model (as preserving
`post5` in the previous example is definitely wrong), and also
post-releases are extremely obscure so probably no one will notice. In
the cases where this behaviour isn't useful, you probably wanted to pass
`--bump patch` or something anyway which *should* definitely clear the
`post5` (putting it another way: the only cases where `--bump stable`
has dubious behaviour is when you wanted it to do a noop, which, is a
command you could have just not written at all).

In all cases we preserve the "epoch" and "local" components of a
version, so the `7!` and `+local` in `7!1.2.3+local` will never be
modified by `--bump` (you can use the raw version set mode if you want
to touch those). The preservation of `local` is another slightly odd
choice, but it's a really obscure feature (so again it mostly won't come
up) and when it's used it seems to mostly be used for referring to
variant releases, in which case preserving it tends to be correct.

Fixes #13223

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-10 08:45:17 -05:00
荆长逯
42fcc81b3d
chore: remove redundant words in comment (#14532)
<!--
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

remove redundant words in comment

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

## Test Plan

<!-- How was it tested? -->

Signed-off-by: jingchanglu <jingchanglu@outlook.com>
2025-07-10 08:25:38 -05:00
Zanie Blue
573b991398
Add nesting groups documentation for dependency groups (#14539) 2025-07-10 08:10:21 -05:00
Arthur Kim
f900ef9e57
setup-python/v5 exists, v6 don't exists. (#14533)
## Summary

I suddenly found wrong documentation with setup-python in
https://docs.astral.sh/uv/guides/integration/github/#setting-up-python.

`setup-python/v5` exists, `setup-python/v6` don't exists.


## Test Plan

nothing
2025-07-10 06:17:30 -05:00
github-actions[bot]
92716606e5
Sync latest Python releases (#14531)
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
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-10 00:40:58 +00:00
konsti
803eb338a3
Simplify relative URL handling (#14449)
I was trying to figure out what the correct relative-and-absolute URL
handling function was and realized there are two and they are redundant.
2025-07-09 23:20:02 +00:00
Zanie Blue
2514203964
Add missing 0.7.20 changelog entry (#14528)
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
2025-07-09 20:36:08 +00:00
konsti
e798b09aa4
Multiple modules in namespace packages (#14460)
Support multiple root modules in namespace packages by enumerating them:

```toml
[tool.uv.build-backend]
module-name = ["foo", "bar"]
```

This allows applications with multiple root packages without migrating
to workspaces. Since those are regular module names (we iterate over
them an process each one like a single module names), it allows
combining dotted (namespace) names and regular names. It also
technically allows combining regular and stub modules, even though this
is even less recommends.

We don't recommend this structure (please use a workspace instead, or
structure everything in one root module), but it reduces the number of
cases that need `namespace = true`.

Fixes #14435
Fixes #14438

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-09 17:45:44 +00:00
Zanie Blue
812a3e7c34
Bump version to 0.7.20 (#14525) 2025-07-09 12:15:41 -05:00
Kevin Nakamura
1958aa26bd
Add debug message when skipping Python downloads (#14509)
# Description
Several users, myself included, had some issues with Anki (recently
migrated to uv).

https://forums.ankiweb.net/t/bug-anki-25-07-fails-to-launch-on-linux/63475

zanieb came in and gave us pointers, including looking at our uv logs. 
https://github.com/ankitects/anki/pull/4074#issuecomment-3046992777
log: https://github.com/Grinkers/uv/pull/1#issuecomment-3047538135

The actual issue was that I had a system config in /etc/uv/uv.toml but
uv wasn't giving useful feedback for its combining/unification.

A higher level issue is that there's nice logs, however logging is
initialized after! We want to log files read, but need to read the files
to know what log level to use.

7e48292fac/crates/uv-settings/src/lib.rs (L68)

7e48292fac/crates/uv/src/lib.rs (L354)

zanieb mentioned there's https://github.com/astral-sh/uv/issues/13123,
so consider this a +1 to that.

## Result
The end of the output will be:
```
DEBUG Downloads disabled. Skipping...
DEBUG Released lock at `/tmp/uv-823c7b0e73da3e08.lock`
error: No interpreter found for Python 3.13.5 in managed installations
```

Sorry for the minuscule sized PR. Feel free to close if there's a bigger
logging pass.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-09 15:56:48 +00:00
Charlie Marsh
57338e558c
Drop trailing arguments when writing shebangs (#14519)
## Summary

You can see in pip that they read the full first line, then replace it
with the rewritten shebang, thereby dropping any trailing arguments on
the shebang:
65da0ff534/src/pip/_internal/operations/install/wheel.py (L94)

In contrast, we currently retain them, but write them _after_ the
shebang, which is wrong.

Closes https://github.com/astral-sh/uv/issues/14470.
2025-07-09 10:51:06 -05:00
Charlie Marsh
4d061a6fc3
Add --workspace flag to uv add (#14496)
## Summary

You can now pass `--workspace` to `uv add` to add a path dependency as a
workspace member.

Closes https://github.com/astral-sh/uv/issues/14464.
2025-07-09 11:46:53 -04:00
Yu, Guangye
b1dc2b71a3
Add auto-detection for Intel GPUs (#14386)
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
## Summary

This PR intends to enable `--torch-backend=auto` to detect Intel GPUs
automatically:
- On Linux, detection is performed using the `lspci` command via
`Display controller` id.
- On Windows, ~~detection is done via a `powershell` query to
`Win32_VideoController`~~. Skip support for now—revisit once a better
solution is available.

Currently, Intel GPUs (XPU) do not rely on specific driver or toolkit
versions to distribute different PyTorch wheels.

## Test Plan

<!-- How was it tested? -->
On Linux:

![image](https://github.com/user-attachments/assets/f7f238e3-a797-42ea-b8fa-9b028dfd4db5)
~~On Windows:

![image](https://github.com/user-attachments/assets/a10d774e-1cb9-431b-bb85-e3e8225df98f)~~

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-07-09 13:31:08 +00:00
Zanie Blue
2709c441a8
Revert normalization of trailing slashes on index URLs (#14511)
Reverts:

- #14349
- #14346
- #14245

Retains the test cases. Includes a `find-links` test case.

Supersedes

- https://github.com/astral-sh/uv/pull/14387
- https://github.com/astral-sh/uv/pull/14503

We originally got a report at
https://github.com/astral-sh/uv/issues/13707 that inclusion of a
trailing slash on an index URL was causing lockfile churn despite having
no semantic meaning and resolved the issue by adding normalization that
stripped trailing slashes at parse time.

We then discovered that, while there are not semantic differences for
trailing slashes on Simple API index URLs, there are differences for
some flat (or find links) indexes. As reported in
https://github.com/astral-sh/uv/issues/14367, the change in
https://github.com/astral-sh/uv/pull/14245 caused a regression for at
least one user.

We attempted to fix the regression via a few approaches.

https://github.com/astral-sh/uv/pull/14387 attempted to differentiate
between Simple API and flat index URL parsing, but failed to account for
the `Deserialize` implementation, which always assumed Simple API-style
index URLs and incorrectly trimmed trailing slashes in various cases
where we deserialized the `IndexUrl` type from a file. I attempted to
resolve this by performing a larger refactor, but it ended up being
quite painful. In particular, the `Index` type was a blocker — we don't
know the `IndexUrl` variant until we've parsed the `IndexFormat` and
having a multi-stage deserializer is not appealing but adding a new
intermediate type (i.e., `RawIndex`) is painful due to the pervasiveness
of `Index`. Given that we've regressed behavior here and there's not a
straight-forward fix, we're reverting the normalization entirely.

https://github.com/astral-sh/uv/pull/14503 attempted to perform
normalization at compare-time, but that means we'd fail to invalidate
the lockfile when the a trailing slash was added or removed and given
that a trailing slash has semantic meaning for a find-links URL... we'd
have another correctness problem.

After this revert, we'll retain all index URLs verbatim. The downside to
this approach is that we'll be adding a bunch of trailing slashes back
to lockfiles that we previously normalized out, and we'll be reverting
our fix for users with inconsistent trailing slashes on their index
URLs. Users affected by the original motivating issue should use
consistent trailing slashes on their URLs, as they do frequently have
semantic meaning. We may want to revisit normalization and type aware
index URL parsing as part of a larger change.

Closes  https://github.com/astral-sh/uv/issues/14367
2025-07-09 06:50:31 -05:00
github-actions[bot]
afcbcc7498
Sync latest Python releases (#14514)
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
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-08 21:12:22 -05:00
Charlie Marsh
5e2dc5a9aa
Remove uv pip sync suggestion with pyproject.toml (#14510)
Some checks are pending
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 | conda3.8 on linux x86-64 (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 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 | 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.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
## Summary

I think doing this would almost always be a mistake, since it won't
install any transitive dependencies. Instead, I took the opportunity to
mention the `pylock.toml` format.

Closes
https://github.com/astral-sh/uv/issues/14507#issuecomment-3050083116.
2025-07-08 16:13:02 -04:00
Zanie Blue
7e48292fac
Fix handling of pre-releases in preferences (#14498)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 | 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
Closes https://github.com/astral-sh/uv/issues/14485

I tested this using the reproduction in the issue. It'd be nice to add
test coverage though.
2025-07-07 20:10:35 -05:00
github-actions[bot]
e31f556205
Sync latest Python releases (#14452)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-08 00:53:38 +00:00
Zanie Blue
dedced3265
Remove cache-dependency-glob examples for setup-uv (#14493)
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
See https://github.com/astral-sh/uv/pull/13163#discussion_r2063244551
2025-07-07 15:06:23 -05:00
theirix
5c6d76ca8b
Update documentation for GHA to use v6 (#14490)
## Summary

`astral-sh/setup-uv@v6` is the latest version of GitHub actions.

## Test Plan

Documentation update
2025-07-07 14:04:45 -05:00
Nils Koch
1d20530f2d
trim content of INSTALLER file (#14488)
<!--
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

We are using UV as a library and `installer()` returned `"pip\n"`. The
packages got installed by the pip package manager and not by UV. pip
seems to add a new line to the `INSTALLER` file and UV does not.

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

## Test Plan

<!-- How was it tested? -->
2025-07-07 18:16:50 +02:00
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
Zanie Blue
38ee6ec800
Bump version to 0.7.19 (#14431) 2025-07-02 21:19:52 +00:00
konsti
71b5ba13d7
Stabilize the uv build backend (#14311)
The uv build backend has gone through some feedback cycles, we expect no
more major configuration changes, and we're ready to take the next step:
The uv build backend in stable.

This PR stabilizes:

* Using `uv_build` as build backend
* The documentation of the uv build backend
* The direct build fast path, where uv doesn't use PEP 517 if you're
using `uv_build` in a compatible version.
* `uv build --list`, which is limited to `uv_build`.

It does not:
* Make `uv_build` the default on `uv init`
* Make `--package` the default on `uv init`
2025-07-02 15:37:43 -05:00
Zanie Blue
5f2857a1c7
Add linux aarch64 smoke tests (#14427)
Testing https://github.com/astral-sh/uv/pull/14426
2025-07-02 15:18:46 -05:00
Zanie Blue
a58969feef
Fix workspace_unsatisfiable_member_dependencies (#14429) 2025-07-02 15:11:50 -05:00
github-actions[bot]
3bb8ac610c
Sync latest Python releases (#14426)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-02 14:51:17 -05:00
Jack O'Connor
ec54dce919
Includes sys.prefix in cached environment keys to avoid --with collisions across projects (#14403)
Fixes https://github.com/astral-sh/uv/issues/12889.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-02 14:40:18 -05:00
Zanie Blue
a6bb65c78d
Clarify behavior and hint on tool install when no executables are available (#14423)
Some checks are pending
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 / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (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 | 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 | 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
Closes https://github.com/astral-sh/uv/issues/14416
2025-07-02 13:11:17 -05:00
Charlie Marsh
743260b1f5
Make project and interpreter lock acquisition non-fatal (#14404)
## Summary

If we fail to acquire a lock on an environment, uv shouldn't fail; we
should just warn. In some cases, users run uv with read-only permissions
for their projects, etc.

For now, I kept any locks acquired _in the cache_ as hard failures,
since we always need write-access to the cache.

Closes https://github.com/astral-sh/uv/issues/14411.
2025-07-02 14:03:43 -04:00
Zanie Blue
2f53ea5c5c
Add a migration guide from pip to uv projects (#12382)
[Rendered](https://github.com/astral-sh/uv/blob/zb/pip-wip/docs/guides/migration/pip-to-project.md)

---------

Co-authored-by: samypr100 <3933065+samypr100@users.noreply.github.com>
Co-authored-by: Mathieu Kniewallner <mathieu.kniewallner@gmail.com>
Co-authored-by: Aria Desires <aria.desires@gmail.com>
2025-07-02 12:25:19 -05:00
Charlie Marsh
a9ea756d14
Ignore Python patch version for --universal pip compile (#14405)
## Summary

The idea here is that if a user runs `uv pip compile --universal`, we
should ignore the patch version on the current interpreter. I think this
makes sense... `--universal` tries to resolve for all future versions,
so it seems a bit odd that we'd start at the _current_ patch version.

Closes https://github.com/astral-sh/uv/issues/14397.
2025-07-02 11:11:51 -04:00
Zanie Blue
43f67a4a4c
Update the tilde version specifier warning to include more context (#14335)
Follows https://github.com/astral-sh/uv/pull/14008
2025-07-02 09:08:45 -05:00
konsti
a7aa46acc5
Add a "choosing a build backend" section to the docs (#14295)
I think the build backend docs as a whole are now ready for review. I
only made a small change here.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-07-02 09:02:03 -05:00
Zanie Blue
b0db548c80
Bump the test timeout from 90s -> 120s (#14170)
In hopes of resolving https://github.com/astral-sh/uv/issues/14158

We should also see why the tests are so slow though.
2025-07-02 13:39:58 +00:00
konsti
bf5dcf9929
Reduce index credential stashing code duplication (#14419)
Reduces some duplicate code around index credentials.
2025-07-02 15:25:56 +02:00
John Mumm
e40d3d5dff
Re-enable Artifactory in the registries integration test (#14408)
Having worked out the account issue, I've re-enabled Artifactory in the
registries test.
2025-07-02 13:50:35 +02:00
Zanie Blue
87e9ccfb92
Bump version to 0.7.18 (#14402)
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
2025-07-01 15:30:44 -05:00
konsti
06df95adbf
Workaround for panic due to missing global validation in clap (#14368)
Clap does not perform global validation, so flag that are declared as
overriding can be set at the same time:
https://github.com/clap-rs/clap/issues/6049. This would previously cause
a panic. We work around this by choosing the yes-value always and
writing a warning.

An alternative would be erroring when both are set, but it's unclear to
me if this may break things we want to support. (`UV_OFFLINE=1 cargo run
-q pip --no-offline install tqdm --no-cache` is already banned).

Fixes https://github.com/astral-sh/uv/pull/14299

**Test Plan**

```
$ cargo run -q pip --offline install --no-offline tqdm --no-cache
  warning: Boolean flags on different levels are not correctly supported (https://github.com/clap-rs/clap/issues/6049)
    × No solution found when resolving dependencies:
    ╰─▶ Because tqdm was not found in the cache and you require tqdm, we can conclude that your requirements are unsatisfiable.

        hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache.
```
2025-07-01 13:39:46 -05:00
John Mumm
29fcd6faee
Fix test cases to match Cow variants (#14390)
Updates `without_trailing_slash` and `without_fragment` to separately
match values against `Cow` variants.

Closes #14350
2025-07-01 13:39:17 -05:00
Charlie Marsh
d9f9ed4aec
Reuse build (virtual) environments across resolution and installation (#14338)
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
## Summary

The basic idea here is that we can (should) reuse a build environment
across resolution (`prepare_metadata_for_build_wheel`) and installation.
This also happens to solve the build-PyTorch-from-source problem, since
we use a consistent build environment between the invocations.

Since `SourceDistributionBuilder` is stateless, we instead store the
builds on `BuildContext`, and we key them by various properties: the
underlying interpreter, the configuration settings, etc. This just
ensures that if we build the same package twice within a process, we
don't accidentally reuse an incompatible build (virtual) environment.
(Note that still drop build environments at the end of the command, and
don't attempt to reuse them across processes.)

Closes #14269.
2025-07-01 13:15:47 -04:00
Jack O'Connor
85358fe9c6 Keep track of retries in ManagedPythonDownload::fetch_with_retry
If/when we see https://github.com/astral-sh/uv/issues/14171 again, this
should clarify whether our retry logic was skipped (i.e. a transient
error wasn't correctly identified as transient), or whether we exhausted
our retries. Previously, if you ran a local example fileserver as in
https://github.com/astral-sh/uv/issues/14171#issuecomment-3014580701 and
then you tried to install Python from it, you'd get:

```
$ export UV_TEST_NO_CLI_PROGRESS=1
$ uv python install 3.8.20 --mirror http://localhost:8000 2>&1 | cat
error: Failed to install cpython-3.8.20-linux-x86_64-gnu
  Caused by: Failed to extract archive: cpython-3.8.20-20241002-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz
  Caused by: failed to unpack `/home/jacko/.local/share/uv/python/.temp/.tmpS4sHHZ/python/lib/libpython3.8.so.1.0`
  Caused by: failed to unpack `python/lib/libpython3.8.so.1.0` into `/home/jacko/.local/share/uv/python/.temp/.tmpS4sHHZ/python/lib/libpython3.8.so.1.0`
  Caused by: error decoding response body
  Caused by: request or response body error
  Caused by: error reading a body from connection
  Caused by: Connection reset by peer (os error 104)
```

With this change you get:

```
error: Failed to install cpython-3.8.20-linux-x86_64-gnu
  Caused by: Request failed after 3 retries
  Caused by: Failed to extract archive: cpython-3.8.20-20241002-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz
  Caused by: failed to unpack `/home/jacko/.local/share/uv/python/.temp/.tmp4Ia24w/python/lib/libpython3.8.so.1.0`
  Caused by: failed to unpack `python/lib/libpython3.8.so.1.0` into `/home/jacko/.local/share/uv/python/.temp/.tmp4Ia24w/python/lib/libpython3.8.so.1.0`
  Caused by: error decoding response body
  Caused by: request or response body error
  Caused by: error reading a body from connection
  Caused by: Connection reset by peer (os error 104)
```

At the same time, I'm updating the way we handle the retry count to
avoid nested retry loops exceeding the intended number of attempts, as I
mentioned at
https://github.com/astral-sh/uv/issues/14069#issuecomment-3020634281.
It's not clear to me whether we actually want this part of the change,
and I need feedback here.
2025-07-01 09:52:19 -07:00
Charlie Marsh
c078683217
Only drop build directories on program exit (#14304)
## Summary

This PR ensures that we avoid cleaning up build directories until the
end of a resolve-and-install cycle. It's not bulletproof (since we could
still run into issues with `uv lock` followed by `uv sync` whereby a
build directory gets cleaned up that's still referenced in the `build`
artifacts), but it at least gets PyTorch building without error with `uv
pip install .`, which is a case that's been reported several times.

Closes https://github.com/astral-sh/uv/issues/14269.
2025-07-01 12:50:19 -04:00
Zanie Blue
c777491bf4
Use the insiders requirements when building docs in CI (#14379) 2025-07-01 11:29:10 -05:00
konsti
9af3e9b6ec
Remove unnecessary codspeed deps (#14396)
See https://github.com/CodSpeedHQ/codspeed-rust/pull/108
2025-07-01 11:00:30 -05:00
konsti
43745d2ecf
Fix equals-star and tilde-equals with python_version and python_full_version (#14271)
The marker display code assumes that all versions are normalized, in
that all trailing zeroes are stripped. This is not the case for
tilde-equals and equals-star versions, where the trailing zeroes (before
the `.*`) are semantically relevant. This would cause path
dependent-behavior where we would get a different marker string
depending on whether a version with or without a trailing zero was added
to the cache first.

To handle both equals-star and tilde-equals when converting
`python_version` to `python_full_version` markers, we have to merge the
version normalization (i.e. trimming the trailing zeroes) and the
conversion both to `python_full_version` and to `Ranges`, while special
casing equals-star and tilde-equals.

To avoid churn in lockfiles, we only trim in the conversion to `Ranges`
for markers, but keep using untrimmed versions for requires-python.
(Note that this behavior is technically also path dependent, as versions
with and without trailing zeroes have the same Hash and Eq. E.q.,
`requires-python == ">= 3.10.0"` and `requires-python == ">= 3.10"` in
the same workspace could lead to either value in `uv.lock`, and which
one it is could change if we make unrelated (performance) changes.
Always trimming however definitely changes lockfiles, a churn I wouldn't
do outside another breaking or lockfile-changing change.) Nevertheless,
there is a change for users who have `requires-python = "~= 3.12.0"` in
their `pyproject.toml`, as this now hits the correct normalization path.

Fixes #14231
Fixes #14270
2025-07-01 17:48:48 +02:00
Charlie Marsh
3774a656d7
Use parsed URLs for conflicting URL error message (#14380)
## Summary

There's a good example of the downside of using verbatim URLs here:
https://github.com/astral-sh/uv/pull/14197#discussion_r2163599625 (we
show two relative paths that point to the same directory, but it's not
clear from the error message).

The diff:

```
    2     2 │ ----- stdout -----
    3     3 │
    4     4 │ ----- stderr -----
    5     5 │ error: Requirements contain conflicting URLs for package `library` in all marker environments:
    6       │-- ../../library
    7       │-- ./library
          6 │+- file://[TEMP_DIR]/library
          7 │+- file://[TEMP_DIR]/library (editable)
```
2025-07-01 08:18:01 -04:00
Zanie Blue
b1812d111a
Edits to the build backend documentation (#14376)
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
Co-authored-by: konstin <konstin@mailbox.org>
2025-07-01 08:44:23 +00:00
github-actions[bot]
a3db9a9ae4
Sync latest Python releases (#14381)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-07-01 03:44:18 +00:00
renovate[bot]
c5ca240fb7
Update PyO3/maturin-action action to v1.49.3 (#14363)
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
2025-06-30 19:16:53 -04:00
renovate[bot]
7bbdc08dae
Update depot/build-push-action action to v1.15.0 (#14361) 2025-06-30 19:16:46 -04:00
renovate[bot]
5f8d4bbf02
Update Rust crate indexmap to v2.10.0 (#14365) 2025-06-30 19:16:31 -04:00
Adrien Cacciaguerra
9e9505df50
Bump CodSpeed to v3 (#14371)
## Summary

<!-- What's the purpose of the change? What does it do, and why? -->
As explained in the [`codspeed-rust` v3 release
notes](https://github.com/CodSpeedHQ/codspeed-rust/releases/tag/v3.0.0),
the `v3` of the compatibility layers is now required to work with the
latest version(`v3`) of `cargo-codspeed`.
2025-06-30 17:58:29 -05:00
Aria Desires
2f9061dcd0
Update python, add support for installing arm windows pythons (#14374) 2025-06-30 22:02:19 +00:00
Aria Desires
317ce6e245
disfavor aarch64 windows in its own house (#13724)
and prefer emulated x64 windows in its stead.

This is preparatory work for shipping support for uv downloading and
installing aarch64 (arm64) windows Pythons. We've [had builds for this
platform ready for a
while](https://github.com/astral-sh/python-build-standalone/pull/387),
but have held back on shipping them due to a fundamental problem:

**The Python packaging ecosystem does not have strong support for
aarch64 windows**, e.g., not many projects build aarch64 wheels yet. The
net effect of this is that, if we handed you an aarch64 python
interpreter on windows, you would have to build a lot more sdists, and
there's a high chance you will simply fail to build that sdist and be
sad.

Yes unfortunately, in this case a non-native Python interpreter simply
*works better* than the native one... in terms of working at all, today.
Of course, if the native interpreter works for your project, it should
presumably have better performance and platform compatibility.

We do not want to stand in the way of progress, as ideally this
situation is a temporary state of affairs as the ecosystem grows to
support aarch64 windows. To enable progress, on aarch64 Windows builds
of uv:

* We will still use a native python interpreter, e.g., if it's at the
front of your `PATH` or the only installed version.
* If we are choosing between equally good interpreters that differ in
architecture, x64 will be preferred.
* If the aarch64 version is newer, we will prefer the aarch64 one.
* We will emit a diagnostic on installation, and show the python request
to pass to uv to force aarch64 windows to be used.
* Will be shipping [aarch64 Windows Python
downloads](https://github.com/astral-sh/python-build-standalone/pull/387)
* Will probably add some kind of global override setting/env-var to
disable this behaviour.
* Will be shipping this behaviour in
[astral-sh/setup-uv](https://github.com/astral-sh/setup-uv)

We're coordinating with Microsoft, GitHub (for the `setup-python`
action), and the CPython team (for the `python.org` installers), to
ensure we're aligned on this default and the timing of toggling to
prefer native distributions in the future.

See discussion in 

- https://github.com/astral-sh/uv/issues/12906

---

This is an alternative to 

* #13719 

which uses sorting rather than filtering, as discussed in 

* #13721
2025-06-30 17:42:00 -04:00
Zanie Blue
1c7c174bc8
Include the canonical path in the interpreter query cache key (#14331)
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 | 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 fixes an obscure cache collision in Python interpreter queries,
which we believe to be the root cause of CI flakes we've been seeing
where a project environment is invalidated and recreated.

This work follows from the logs in [this CI
run](4495059999)
which captured one of the flakes with tracing enabled. There, we can see
that the project environment is invalidated because the Python
interpreter in the environment has a different version than expected:

```
DEBUG Checking for Python environment at `.venv`
TRACE Cached interpreter info for Python 3.12.9, skipping probing: .venv/bin/python3
DEBUG The interpreter in the project environment has different version (3.12.9) than it was created with (3.9.21)
```

(this message is updated to reflect #14329)

The flow is roughly:

- We create an environment with 3.12.9
- We query the environment, and cache the interpreter version for
`.venv/bin/python`
- We create an environment for 3.9.12, replacing the existing one
- We query the environment, and read the cached information

The Python cache entries are keyed by the absolute path to the
interpreter, and rely on the modification time (ctime, nsec resolution)
of the canonicalized path to determine if the cache entry should be
invalidated. The key is a hex representation of a u64 sea hasher output
— which is very unlikely to collide.

After an audit of the Python query caching logic, we determined that the
most likely cause of a collision in cache entries is that the
modification times of underlying interpreters are identical. This seems
pretty feasible, especially if the file system does not support
nanosecond precision — though it appears that the GitHub runners do
support it.

The fix here is to include the canonicalized path in the cache key,
which ensures we're looking at the modification time of the _same_
underlying interpreter.

This will "invalidate" all existing interpreter cache entries but that's
not a big deal.

This should also have the effect of reducing cache churn for
interpreters in virtual environments. Now, when you change Python
versions, we won't invalidate the previous cache entry so if you change
_back_ to the old version we can re-use our cached information.

It's a bit speculative, since we don't have a deterministic reproduction
in CI, but this is the strongest candidate given the logs and should
increase correctness regardless.

Closes https://github.com/astral-sh/uv/issues/14160
Closes https://github.com/astral-sh/uv/issues/13744
Closes https://github.com/astral-sh/uv/issues/13745

Once it's confirmed the flakes are resolved, we should revert

- https://github.com/astral-sh/uv/pull/14275
- #13817
2025-06-30 15:39:47 +00:00
konsti
0372a5b05d
Ignore invalid build backend settings when not building (#14372)
Fixes #14323
2025-06-30 16:32:28 +02:00
Ondrej Profant
ae500c95d2
Docs: add instructions for publishing to JFrog's Artifactory (#14253)
## Summary

Add instructions for publishing to JFrog's Artifactory into
[documentation](https://docs.astral.sh/uv/guides/integration/alternative-indexes/).

Related issues:
https://github.com/astral-sh/uv/issues/9845
https://github.com/astral-sh/uv/issues/10193

## Test Plan

I ran the documentation locally and use npx prettier.

---------

Co-authored-by: Ondrej Profant <ondrej.profant@datamole.ai>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-30 13:58:55 +00:00
renovate[bot]
5cfabd7085
Update Rust crate schemars to v1.0.3 (#14358)
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.0` -> `1.0.3` |

---

> [!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.3`](https://redirect.github.com/GREsau/schemars/blob/HEAD/CHANGELOG.md#103---2025-06-28)

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

##### Fixed

- Fix compile error when a doc comment is set on both a `transparent`
(or newtype) struct and its field
([https://github.com/GREsau/schemars/issues/446](https://redirect.github.com/GREsau/schemars/issues/446))
- Fix `json_schema!()` macro compatibility when used from pre-2021 rust
editions
([https://github.com/GREsau/schemars/pull/447](https://redirect.github.com/GREsau/schemars/pull/447))

###
[`v1.0.2`](https://redirect.github.com/GREsau/schemars/blob/HEAD/CHANGELOG.md#102---2025-06-26)

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

##### Fixed

- Fix schema properties being incorrectly reordered during serialization
([https://github.com/GREsau/schemars/issues/444](https://redirect.github.com/GREsau/schemars/issues/444))

###
[`v1.0.1`](https://redirect.github.com/GREsau/schemars/blob/HEAD/CHANGELOG.md#101---2025-06-24)

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

##### Fixed

- Deriving `JsonSchema` with `no_std` broken due to
`std::borrow::ToOwned` trait not being in scope
([https://github.com/GREsau/schemars/issues/441](https://redirect.github.com/GREsau/schemars/issues/441))

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-06-30 13:39:20 +00:00
renovate[bot]
15551a0201
Update Swatinem/rust-cache action to v2.8.0 (#14366)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [Swatinem/rust-cache](https://redirect.github.com/Swatinem/rust-cache)
| action | minor | `v2.7.8` -> `v2.8.0` |

---

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

---

### Release Notes

<details>
<summary>Swatinem/rust-cache (Swatinem/rust-cache)</summary>

###
[`v2.8.0`](https://redirect.github.com/Swatinem/rust-cache/releases/tag/v2.8.0)

[Compare
Source](https://redirect.github.com/Swatinem/rust-cache/compare/v2.7.8...v2.8.0)

##### What's Changed

- Add cache-workspace-crates feature by
[@&#8203;jbransen](https://redirect.github.com/jbransen) in
[https://github.com/Swatinem/rust-cache/pull/246](https://redirect.github.com/Swatinem/rust-cache/pull/246)
- Feat: support warpbuild cache provider by
[@&#8203;stegaBOB](https://redirect.github.com/stegaBOB) in
[https://github.com/Swatinem/rust-cache/pull/247](https://redirect.github.com/Swatinem/rust-cache/pull/247)

##### New Contributors

- [@&#8203;jbransen](https://redirect.github.com/jbransen) made their
first contribution in
[https://github.com/Swatinem/rust-cache/pull/246](https://redirect.github.com/Swatinem/rust-cache/pull/246)
- [@&#8203;stegaBOB](https://redirect.github.com/stegaBOB) made their
first contribution in
[https://github.com/Swatinem/rust-cache/pull/247](https://redirect.github.com/Swatinem/rust-cache/pull/247)

**Full Changelog**:
https://github.com/Swatinem/rust-cache/compare/v2.7.8...v2.8.0

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 12:24:54 +02:00
renovate[bot]
61482da319
Update pre-commit hook astral-sh/ruff-pre-commit to v0.12.1 (#14362)
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 | minor | `v0.11.13` -> `v0.12.1` |

---

> [!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.1`](https://redirect.github.com/astral-sh/ruff-pre-commit/releases/tag/v0.12.1)

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

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

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

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

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

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 12:13:33 +02:00
renovate[bot]
b2979d25a8
Update acj/freebsd-firecracker-action action to v0.5.1 (#14355)
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 | 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
2025-06-29 22:19:38 -04:00
renovate[bot]
e44a64ee13
Update Rust crate windows-registry to v0.5.3 (#14359) 2025-06-29 22:18:26 -04:00
renovate[bot]
e9533a0e29
Update aws-actions/configure-aws-credentials digest to 3d8cba3 (#14354) 2025-06-29 22:18:12 -04:00
renovate[bot]
40386e438f
Update Rust crate owo-colors to v4.2.2 (#14357) 2025-06-29 22:17:59 -04:00
renovate[bot]
a8b838dee9
Update astral-sh/setup-uv action to v6.3.1 (#14360) 2025-06-29 22:17:48 -04:00
renovate[bot]
d7e1fced43
Update Rust crate cargo-util to v0.2.21 (#14356) 2025-06-29 22:17:41 -04:00
Charlie Marsh
7603153f5b
Allow alpha, beta, and rc prefixes in tests (#14352)
Some checks are pending
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 | 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
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
## Summary

A bunch of tests currently fail if you try to use a pre-release version.
This PR makes the regular expressions more lenient.
2025-06-29 19:30:52 +00:00
Charlie Marsh
d15efb7d91
Add an IntoIterator for FormMetadata (#14351)
## Summary

Clippy would lint for this if the symbol were public as a matter of API
hygiene, so adding it.
2025-06-29 15:07:07 -04:00
Zanie Blue
17b7eec287
Consistently normalize trailing slashes on URLs with no path segments (#14349)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on fedora (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 | 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
Alternative to https://github.com/astral-sh/uv/pull/14348
2025-06-29 12:25:10 -05:00
Zanie Blue
c0ebe6871d
Improve trace message for cached Python interpreter query (#14328) 2025-06-29 09:40:29 -05:00
Charlie Marsh
41c218a89b
Bump version to 0.7.17 (#14347) 2025-06-29 09:58:33 -04:00
Charlie Marsh
734b228edf
Drop trailing slashes when converting index URL from URL (#14346)
## Summary

In #14245, we started normalizing index URLs by dropping the trailing
slash in the lockfile. We added tests to ensure that this didn't cause
existing lockfiles to be invalidated, but we missed one of the
constructors (specifically, the path that's used with
`tool.uv.sources`).
2025-06-29 09:36:13 -04:00
Zanie Blue
f9d3f8ea3b
Fix error message ordering for pyvenv.cfg version conflict (#14329)
These were reversed, and we're missing an "a".
2025-06-29 09:19:05 -04:00
Zanie Blue
ec18f4813a
Fix typo (#14341)
Some checks failed
CI / check cache | ubuntu (push) Has been cancelled
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 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 | pyston (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 | 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
2025-06-28 11:32:03 -05:00
Zanie Blue
0cfbdcec09
Ignore UV_PYTHON_CACHE_DIR when empty (#14336)
To match our semantics elsewhere
2025-06-28 09:42:27 -05:00
Zanie Blue
608a1020c6
Update the Python query cache comment (#14330) 2025-06-28 09:42:23 -05:00
Zanie Blue
692667cbb0
Use the canonical ImplementationName -> &str implementation (#14337)
Motivated by some code duplication highlighted in
https://github.com/astral-sh/uv/pull/14201, I noticed we weren't taking
advantage of the existing implementation for casting to a str here.
Unfortunately, we do need a special case for CPython still.
2025-06-28 09:42:18 -05:00
github-actions[bot]
db14cc3005
Sync latest Python releases (#14339)
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 | 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
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-06-28 03:08:53 +00:00
Charlie Marsh
731689e503
Apply build constraints when resolving --with dependencies (#14340)
## Summary

We were applying these at install time, but not resolve time.
2025-06-28 01:39:35 +00:00
Zanie Blue
b6b7409d13
Bump version to 0.7.16 (#14334)
Some checks are pending
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (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 | 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
2025-06-27 16:46:36 -05:00
Aaron Ang
eab938b7b4
Warn users on ~= python version specifier (#14008)
Close #7426

## Summary

Picking up on #8284, I noticed that the `requires_python` object already
has its specifiers canonicalized in the `intersection` method, meaning
`~=3.12` is converted to `>=3.12, <4`. To fix this, we check and warn in
`intersection`.

## Test Plan

Used the same tests from #8284.
2025-06-27 15:48:41 -05:00
Charlie Marsh
6a5d2f1ec4
Share workspace cache between lock and sync operations (#14321)
## Summary

Closes #14316.
2025-06-27 14:48:40 -04:00
Charlie Marsh
4eef79e5e8
Avoid rendering desugared prefix matches in error messages (#14195)
## Summary

When the user provides a requirement like `==2.4.*`, we desugar that to
`>=2.4.dev0,<2.5.dev0`. These bounds then appear in error messages, and
worse, they also trick the error message reporter into thinking that the
user asked for a pre-release.

This PR adds logic to convert to the more-concise `==2.4.*`
representation when possible. We could probably do a similar thing for
the compatible release operator (`~=`).

Closes https://github.com/astral-sh/uv/issues/14177.

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-27 18:06:19 +00:00
John Mumm
f892b8564f
Return Cow from UrlString::with_ methods (#14319)
A minor performance improvement as a follow-up to #14245 (and an
accompanying test).
2025-06-27 13:54:52 -04:00
Zanie Blue
74468dac15
Bump python-build-standalone releases to include 3.14.0b3 (#14301)
See
20250626
2025-06-27 12:36:07 -05:00
John Mumm
880c5e4949
Ensure preview default Python installs are upgradeable (#14261)
Python `bin` installations installed with `uv python install --default
--preview` (no version specified) were not being installed as
upgradeable. Instead each link was pointed at the highest patch version
for a minor version. This change ensures that these preview default
installations are also treated as upgradeable.

The PR includes some updates to the related tests. First, it checks the
default install without specified version case. Second, since it's
adding more read link checks, it creates a new `read_link` helper method
to consolidate repeated logic and replace instances of
`#[cfg(unix/windows)` with `if cfg!(unix/windows)`.

Fixes #14247
2025-06-27 19:26:28 +02:00
John Mumm
5754f2f2db
Normalize index URLs to remove trailing slash (#14245)
Some checks are pending
CI / check system | pyston (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | homebrew python on macos aarch64 (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 | 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 updates `IndexUrl` parsing to normalize non-file URLs by
removing trailing slashes. It also normalizes registry source URLs when
using them to validate the lockfile.

Prior to this change, when writing an index URL to the lockfile, uv
would use a trailing slash if present in the provided URL and no
trailing slash otherwise. This can cause surprising behavior. For
example, `uv lock --locked` will fail when a package is added with an
`--index` value without a trailing slash and then `uv lock --locked` is
run with a `pyproject.toml` version of the index URL that contains a
trailing slash. This PR fixes this and adds a test for the scenario.

It might be safe to normalize file URLs in the same way, but since
slashes have a well-defined meaning in the context of files and
directories, I chose not to normalize them here.

Closes #13707.
2025-06-27 17:11:21 +02:00
John Mumm
a824468c8b
Respect URL-encoded credentials in redirect location (#14315)
uv currently ignores URL-encoded credentials in a redirect location.
This PR adds a check for these credentials to the redirect handling
logic. If found, they are moved to the Authorization header in the
redirect request.

Closes #11097
2025-06-27 16:41:14 +02:00
Charlie Marsh
56266447e2
Bump MSRV and rust-toolchain version (#14303)
## Summary

Per our versioning policy, we stay two versions back (and 1.88 was
released today).
2025-06-27 10:27:45 -04:00
Jack O'Connor
efc361223c move the test buckets dir into the canonicalized temp dir
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 | 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
Previously we were using the XDG data dir to avoid symlinks, but there's no
particular guarantee that that's not going to be a symlink too. Using the
canonicalized temp dir by default is also slightly nicer for a couple reasons:
It's sometimes faster (an in-memory tempfs on e.g. Arch), and it makes
overriding `$TMPDIR` or `%TMP%` sufficient to control where tests put temp
files, without needing to override `UV_INTERNAL__TEST_DIR` too.
2025-06-26 14:56:20 -07:00
Zanie Blue
9ee34dc69b
Fix Indexes::new doc (#14293) 2025-06-26 20:40:40 +00:00
Charlie Marsh
326e4497da
Allow local indexes to reference remote files (#14294)
## Summary

Previously, we assumed that local indexes only referenced local files.
However, it's fine for a local index (like, a `file://`-based Simple
API) to reference a remote file, and in fact Pyodide operates this way.

Closes https://github.com/astral-sh/uv/issues/14227.

## Test Plan

Ran `UV_INDEX=$(pyodide config get package_index) cargo run add anyio`,
which produced this lockfile:

```toml
version = 1
revision = 2
requires-python = ">=3.13.2"

[[package]]
name = "anyio"
version = "4.9.0"
source = { registry = "../../../Library/Caches/.pyodide-xbuildenv-0.30.5/0.27.7/xbuildenv/pyodide-root/package_index" }
dependencies = [
    { name = "idna" },
    { name = "sniffio" },
]
wheels = [
    { url = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/anyio-4.9.0-py3-none-any.whl", hash = "sha256:e1d9180d4361fd71d1bc4a7007fea6cae1d18792dba9d07eaad89f2a8562f71c" },
]

[[package]]
name = "foo"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
    { name = "anyio" },
]

[package.metadata]
requires-dist = [{ name = "anyio", specifier = ">=4.9.0" }]

[[package]]
name = "idna"
version = "3.7"
source = { registry = "../../../Library/Caches/.pyodide-xbuildenv-0.30.5/0.27.7/xbuildenv/pyodide-root/package_index" }
wheels = [
    { url = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/idna-3.7-py3-none-any.whl", hash = "sha256:9d4685891e3e37434e09b1becda7e96a284e660c7aea9222564d88b6c3527c09" },
]

[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "../../../Library/Caches/.pyodide-xbuildenv-0.30.5/0.27.7/xbuildenv/pyodide-root/package_index" }
wheels = [
    { url = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:9215f9917b34fc73152b134a3fc0a2eb0e4a49b0b956100cad75e84943412bb9" },
]
```
2025-06-26 20:17:42 +00:00
Charlie Marsh
05ab266200
Avoid using path URL for workspace Git dependencies in requirements.txt (#14288)
## Summary

Closes https://github.com/astral-sh/uv/issues/13020.
2025-06-26 19:48:12 +00:00
Charlie Marsh
c291d4329a
Include path or URL when failing to convert in lockfile (#14292)
## Summary

E.g., in #14227, we now get:

```
error: Failed to convert URL to path: https://cdn.jsdelivr.net/pyodide/v0.27.7/full/sniffio-1.3.1-py3-none-any.whl
```
2025-06-26 19:42:04 +00:00
Jack O'Connor
d4d6ede23b Lock the source tree when running setuptools, to protect concurrent builds
Fixes https://github.com/astral-sh/uv/issues/13703
2025-06-26 12:28:15 -07:00
Jack O'Connor
60528e3e25 Annotate LockedFile with #[must_use]
Standard lock guards have the same annotation, because creating them
without binding them to a local variable is almost always a mistake.
2025-06-26 12:28:15 -07:00
Zanie Blue
1ff8fc0947
Use Flit instead of Poetry for uninstall tests (#14285)
Investigating https://github.com/astral-sh/uv/issues/14158
2025-06-26 18:09:04 +00:00
Zanie Blue
8c27c2b494
Add verbose output on flake for run_groups_requires_python (#14275)
See https://github.com/astral-sh/uv/issues/14160

Same as https://github.com/astral-sh/uv/pull/13817
2025-06-26 12:11:34 -05:00
Zanie Blue
d27cec78b4
Restore snapshot for sync_dry_run (#14274)
In addition to our flake catch, keep a snapshot.

Extends https://github.com/astral-sh/uv/pull/13817
2025-06-26 16:23:37 +00:00
Aria Desires
1e02008d8b
add more proper docker login if (#14278) 2025-06-26 12:05:45 -04:00
Zanie Blue
469246d177
Fix emit_index_annotation_multiple_indexes test case (#14277)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | 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
uv is taken on Test PyPI now, so the existing test fails
2025-06-26 14:58:24 +00:00
John Mumm
a27e60a22f
Temporarily disable Artifactory registry test (#14276)
I'm waiting on a response to get our subscription back up. Then I can
re-enable this. But for now, this would cause failing CI tests.
2025-06-26 09:47:18 -05:00
Daniel Vianna
4b348512c2
GCP Artifact Registry download URLs must have /simple path (#14251)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | 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
2025-06-25 17:35:41 +02:00
John Mumm
4ed9c5791b
Bump version to 0.7.15 (#14254)
Some checks are pending
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (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 | 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
2025-06-25 12:06:41 +02:00
John Mumm
177df19f30
Add check for using minor version link when creating a venv on Windows (#14252)
There was a regression introduced in #13954 on Windows where creating a
venv behaved as if there was a minor version link even if none existed.
This PR adds a check to fix this.

Closes #14249.
2025-06-25 10:12:32 +02:00
John Mumm
5b2c3595a7
Require disambiguated relative paths for --index (#14152)
We do not currently support passing index names to `--index` for
installing packages. However, we do accept relative paths that can look
like index names. This PR adds the requirement that `--index` values
must be disambiguated with a prefix (`./` or `../` on Unix and Windows
or `.\\` or `..\\` on Windows). For now, if an ambiguous value is
provided, uv will warn that this will not be supported in the future.

Currently, if you provide an index name like `--index test` when there
is no `test` directory, uv will error with a `Directory not found...`
error. That's not very informative if you thought index names were
supported. The new warning makes the context clearer.

Closes #13921
2025-06-25 10:02:06 +02:00
konsti
283323a78a
Allow symlinks in the build backend (#14212)
In workspaces with multiple packages, you usually don't want to include
shared files such as the license repeatedly. Instead, we reading from
symlinked files. This would be supported if we had used std's `is_file`
and read methods, but walkdir's `is_file` does not consider symlinked
files as files.

See https://github.com/astral-sh/uv/issues/3957#issuecomment-2994675003
2025-06-25 07:44:22 +00:00
ya7010
ac788d7cde
Update schemars 1.0.0 (#13693)
Some checks are pending
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 cache | ubuntu (push) Blocked by required conditions
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 | 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 | 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
<!--
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
Update [schemars
0.9.0](https://github.com/GREsau/schemars/releases/tag/v0.9.0)

There are differences in the generated JSON Schema and I will [contact
the author](https://github.com/GREsau/schemars/issues/407).

## Test Plan

---------

Co-authored-by: konstin <konstin@mailbox.org>
2025-06-24 21:43:31 +02:00
Christopher Tee
9fba7a4768
Consistently use Ordering::Relaxed for standalone atomic use cases (#14190) 2025-06-24 12:30:26 -07:00
Christopher Tee
fe11ceedfa
Skip GitHub fast path when rate-limited (#13033) 2025-06-24 12:11:41 -07:00
dmitry-bychkov
61265b0c14
Add a link to PyPI FAQ to clarify what per-project token is. (#14242)
<!--
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

This change adds a link to PyPI FAQ about API tokens on the package
publishing guide page. To me it wasn't clear what are meant in this
section of the docs and it required a little bit of research. Adding
explicit link might help beginners.

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

Co-authored-by: Dmitry Bychkov <dbychkov@alarislabs.com>
2025-06-24 11:56:36 -04:00
Charlie Marsh
606633d35f
Remove wheel filename benchmark (#14240)
## Summary

This flakes often and we don't really need it to be monitored
continuously. We can always revive it from Git later.

Closes https://github.com/astral-sh/uv/issues/13952.
2025-06-24 11:54:12 -04:00
konsti
f20659e1ce
Don't log GitHub fast path usage if it's cached (#14235)
Don't log that we resolved a reference through the GitHub fast path if
we didn't use GitHub at all but used the cached revision. This avoids
stating that the fast path works when it's blocked due to unrelated
reasons (e.g. rate limits).
2025-06-24 11:53:10 -04:00
Charlie Marsh
093e9d6ff0
Add "python-eol" feature to Sphinx tests (#14241)
## Summary

Closes https://github.com/astral-sh/uv/issues/14228.
2025-06-24 11:15:18 -04:00
Ben Beasley
19c58c7fbb
Update wiremock to 0.6.4 (#14238)
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 | 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

In e10881d49c, `uv` started using a fork
of the `wiremock` crate, https://github.com/astral-sh/wiremock-rs,
linking companion PR
https://github.com/LukeMathWalker/wiremock-rs/pull/159. That PR was
merged in `wiremock` 0.6.4, so this PR switches back to the crates.io
version of `wiremock`, with a minimum version of 0.6.4.
<!-- What's the purpose of the change? What does it do, and why? -->

## Test Plan

```
$ cargo run python install
$ cargo test
````
2025-06-24 13:04:55 +00:00
Charlie Marsh
aa2448ef83
Strip query parameters when parsing source URL (#14224)
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 | 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
## Summary

Closes https://github.com/astral-sh/uv/issues/14217.
2025-06-23 14:52:07 -04:00
Charlie Marsh
d9351d52fc
Remove wheel filename-from URL conversion (#14223)
## Summary

This appears to be unused.
2025-06-23 14:26:14 -04:00
Aria Desires
e7f5967111
Don't block docker logins on it being a pull-request (#14222) 2025-06-23 13:30:49 -04:00
Aria Desires
92de53f4eb
Bump version to 0.7.14 (#14218) 2025-06-23 12:48:51 -04:00
John Mumm
2d2dd0c1a3
Update upgrade tests to use 3.10.17 instead of 3.10.8 (#14219)
@oconnor663 discovered that executing `3.10.8` on Arch Linux ran into an
error loading `libcrypt.so.1`. This caused uv to install the latest
patch version on `uv venv` operations during upgrade tests, which
undermined their purpose (since they are checking that if you first
install `3.10.8` and then upgrade, virtual environments are
transparently upgraded). This PR updates the test to use `3.10.17`
instead to avoid this issue.
2025-06-23 18:19:36 +02:00
John Mumm
b06dec8398
Improve Python uninstall perf by removing unnecessary call to installations.find_all() (#14180)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | 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
#13954 introduced an unnecessary slow-down to Python uninstall by
calling `installations.find_all()` to discover remaining installations
after an uninstall. Instead, we can filter all initial installations
against those in `uninstalled`.

As part of this change, I've updated `uninstalled` from a `Vec` to an
`IndexSet` in order to do efficient lookups in the filter. This required
a change I call out below to how we were retrieving them for messaging.
2025-06-23 15:51:44 +02:00
John Mumm
6481aa3e64
Consolidate logic for checking for a virtual environment (#14214)
We were checking whether a path was an executable in a virtual
environment or the base directory of a virtual environment in multiple
places in the codebase. This PR consolidates this logic into one place.

Closes #13947.
2025-06-23 15:12:43 +02:00
renovate[bot]
a9a9e71481
Update google-github-actions/setup-gcloud digest to a8b5801 (#14205)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| google-github-actions/setup-gcloud | action | digest | `77e7a55` ->
`a8b5801` |

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 10:20:59 +00:00
renovate[bot]
ac1405e06c
Update Rust crate syn to v2.0.104 (#14208)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [syn](https://redirect.github.com/dtolnay/syn) |
workspace.dependencies | patch | `2.0.103` -> `2.0.104` |

---

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

---

### Release Notes

<details>
<summary>dtolnay/syn (syn)</summary>

###
[`v2.0.104`](https://redirect.github.com/dtolnay/syn/releases/tag/2.0.104)

[Compare
Source](https://redirect.github.com/dtolnay/syn/compare/2.0.103...2.0.104)

- Disallow attributes on range expression
([#&#8203;1872](https://redirect.github.com/dtolnay/syn/issues/1872))

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 12:07:36 +02:00
renovate[bot]
3e9dbe8b7d
Update Rust crate mimalloc to v0.1.47 (#14207)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [mimalloc](https://redirect.github.com/purpleprotocol/mimalloc_rust) |
dependencies | patch | `0.1.46` -> `0.1.47` |

---

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

---

### Release Notes

<details>
<summary>purpleprotocol/mimalloc_rust (mimalloc)</summary>

###
[`v0.1.47`](https://redirect.github.com/purpleprotocol/mimalloc_rust/releases/tag/v0.1.47):
Version 0.1.47

[Compare
Source](https://redirect.github.com/purpleprotocol/mimalloc_rust/compare/v0.1.46...v0.1.47)

##### Changes

- Mimalloc `v2.2.4`

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 12:07:09 +02:00
renovate[bot]
46221b40c3
Update EmbarkStudios/cargo-deny-action action to v2.0.12 (#14206)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[EmbarkStudios/cargo-deny-action](https://redirect.github.com/EmbarkStudios/cargo-deny-action)
| action | patch | `v2.0.11` -> `v2.0.12` |

---

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

---

### Release Notes

<details>
<summary>EmbarkStudios/cargo-deny-action
(EmbarkStudios/cargo-deny-action)</summary>

###
[`v2.0.12`](https://redirect.github.com/EmbarkStudios/cargo-deny-action/releases/tag/v2.0.12):
Release 2.0.12 - cargo-deny 0.18.3

[Compare
Source](https://redirect.github.com/EmbarkStudios/cargo-deny-action/compare/v2.0.11...v2.0.12)

##### Changed

-
[PR#773](https://redirect.github.com/EmbarkStudios/cargo-deny/pull/773)
changed cargo-deny's duplicate detection to automatically ignore
versions whose only dependent is another version of the same crate.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 12:06:20 +02:00
renovate[bot]
a52595b61a
Update google-github-actions/auth digest to 0920706 (#14204)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| google-github-actions/auth | action | digest | `ba79af0` -> `0920706`
|

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 12:04:50 +02:00
renovate[bot]
7fce3a88b8
Update aws-actions/configure-aws-credentials digest to 3bb878b (#14203)
This PR contains the following updates:

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

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0MC42Mi4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjIuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 12:04:10 +02:00
Charlie Marsh
a82c210cab
Add auto-detection for AMD GPUs (#14176)
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 | pyston (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 | 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
## Summary

Allows `--torch-backend=auto` to detect AMD GPUs. The approach is fairly
well-documented inline, but I opted for `rocm_agent_enumerator` over
(e.g.) `rocminfo` since it seems to be the recommended approach for
scripting:
https://rocm.docs.amd.com/projects/rocminfo/en/latest/how-to/use-rocm-agent-enumerator.html.

Closes https://github.com/astral-sh/uv/issues/14086.

## Test Plan

```
root@rocm-jupyter-gpu-mi300x1-192gb-devcloud-atl1:~# ./uv-linux-libc-11fb582c5c046bae09766ceddd276dcc5bb41218/uv pip install torch --torch-backend=auto
Resolved 11 packages in 251ms
Prepared 2 packages in 6ms
Installed 11 packages in 257ms
 + filelock==3.18.0
 + fsspec==2025.5.1
 + jinja2==3.1.6
 + markupsafe==3.0.2
 + mpmath==1.3.0
 + networkx==3.5
 + pytorch-triton-rocm==3.3.1
 + setuptools==80.9.0
 + sympy==1.14.0
 + torch==2.7.1+rocm6.3
 + typing-extensions==4.14.0
```

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-21 15:21:06 +00:00
Zanie Blue
f0407e4b6f
Only use the release environment in Docker builds on push (#14189)
This drastically reduces the `release` deployment noise, e.g., as seen
in https://github.com/astral-sh/uv/pull/14165
2025-06-21 14:36:07 +00:00
Zanie Blue
b18f45db14
Restore Docker image annotations and fix attestations (#14165)
More follow-up to #13459 

- Depot doesn't support annotations, so we push those manually
- Docker push for the re-tag was breaking the manifest, since we need to
annotate manually, we just do that instead
- We attest after the annotation

A bit of an aside

- We test building the extra images, it's very fast and I don't see why
it's better to gate it

I tested this on my fork then cleaned it up a bit for a commit here. You
can see the images at

- https://github.com/zanieb/uv/pkgs/container/uv 
- https://hub.docker.com/r/astral/uv/tags

---------

Co-authored-by: samypr100 <3933065+samypr100@users.noreply.github.com>
2025-06-21 09:01:20 -05:00
John Mumm
8352560b98
Only update existing symlink directories on preview uninstall (#14179)
Some checks are pending
CI / check cache | ubuntu (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 | 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
On preview uninstall, we should not create a new minor version symlink
directory if one doesn't exist. We should only update existing ones.
2025-06-21 09:50:41 +02:00
Charlie Marsh
0fef253c4b
Use a dedicated type for form metadata (#14175)
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 | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (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.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
2025-06-20 20:33:29 -04:00
Charlie Marsh
e59835d50c
Add XPU to --torch-backend (#14172)
## Summary

Like ROCm, no auto-detection for now.
2025-06-20 20:33:20 -04:00
Jack O'Connor
0133bcc8ca
(f)lock during uv run (#14153)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 | 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 | 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 is very similar to the locking added for `uv sync`, `uv add`, and
`uv remove` in https://github.com/astral-sh/uv/pull/13869. Improving our
(f)locking in general is tracked in
https://github.com/astral-sh/uv/issues/13883.
2025-06-20 20:34:45 +00:00
Zanie Blue
1dbe750452
Refactor PythonVersionFile global loading (#14107)
I was looking into `uv tool` not supporting version files, and noticed
this implementation was confusing and skipped handling like a tracing
log if `--no-config` excludes selection a file. I've refactored it in
preparation for the next change.
2025-06-20 15:31:32 -05:00
Lucas Vittor
563e9495ba
Replace cuda124 with cuda128 (#14168)
## Summary

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

Replace wrong `cuda124` version to the correct `cuda128` version in
torch docs

## Test Plan

<!-- How was it tested? -->
2025-06-20 16:05:17 -04:00
Aria Desires
c710246d76
Update cargo-dist (#14156)
Also took the time to migrate to the external config format to normalize
our projects for team comfort (`ty` *has* to use this format for its
workspace structure).
2025-06-20 14:20:01 -04:00
John Mumm
e9d5780369
Support transparent Python patch version upgrades (#13954)
> NOTE: The PRs that were merged into this feature branch have all been
independently reviewed. But it's also useful to see all of the changes
in their final form. I've added comments to significant changes
throughout the PR to aid discussion.

This PR introduces transparent Python version upgrades to uv, allowing
for a smoother experience when upgrading to new patch versions.
Previously, upgrading Python patch versions required manual updates to
each virtual environment. Now, virtual environments can transparently
upgrade to newer patch versions.

Due to significant changes in how uv installs and executes managed
Python executables, this functionality is initially available behind a
`--preview` flag. Once an installation has been made upgradeable through
`--preview`, subsequent operations (like `uv venv -p 3.10` or patch
upgrades) will work without requiring the flag again. This is
accomplished by checking for the existence of a minor version symlink
directory (or junction on Windows).

### Features

* New `uv python upgrade` command to upgrade installed Python versions
to the latest available patch release:
``` 
# Upgrade specific minor version 
uv python upgrade 3.12 --preview
# Upgrade all installed minor versions
uv python upgrade --preview
```
* Transparent upgrades also occur when installing newer patch versions: 
```
uv python install 3.10.8 --preview
# Automatically upgrades existing 3.10 environments
uv python install 3.10.18
```
* Support for transparently upgradeable Python `bin` installations via
`--preview` flag
```
uv python install 3.13 --preview
# Automatically upgrades the `bin` installation if there is a newer patch version available
uv python upgrade 3.13 --preview
```
* Virtual environments can still be tied to a patch version if desired
(ignoring patch upgrades):
```
uv venv -p 3.10.8
```

### Implementation

Transparent upgrades are implemented using:
* Minor version symlink directories (Unix) or junctions (Windows)
* On Windows, trampolines simulate paths with junctions
* Symlink directory naming follows Python build standalone format: e.g.,
`cpython-3.10-macos-aarch64-none`
* Upgrades are scoped to the minor version key (as represented in the
naming format: implementation-minor version+variant-os-arch-libc)
* If the context does not provide a patch version request and the
interpreter is from a managed CPython installation, the `Interpreter`
used by `uv python run` will use the full symlink directory executable
path when available, enabling transparently upgradeable environments
created with the `venv` module (`uv run python -m venv`)

New types:
* `PythonMinorVersionLink`: in a sense, the core type for this PR, this
is a representation of a minor version symlink directory (or junction on
Windows) that points to the highest installed managed CPython patch
version for a minor version key.
* `PythonInstallationMinorVersionKey`: provides a view into a
`PythonInstallationKey` that excludes the patch and prerelease. This is
used for grouping installations by minor version key (e.g., to find the
highest available patch installation for that minor version key) and for
minor version directory naming.

### Compatibility

* Supports virtual environments created with:
  * `uv venv`
* `uv run python -m venv` (using managed Python that was installed or
upgraded with `--preview`)
  * Virtual environments created within these environments
* Existing virtual environments from before these changes continue to
work but aren't transparently upgradeable without being recreated
* Supports both standard Python (`python3.10`) and freethreaded Python
(`python3.10t`)
* Support for transparently upgrades is currently only available for
managed CPython installations

Closes #7287
Closes #7325
Closes #7892
Closes #9031
Closes #12977

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-20 16:17:13 +02:00
John Mumm
62365d4ec8
Support netrc and same-origin credential propagation on index redirects (#14126)
Some checks are pending
CI / check system | x86-64 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 / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (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 | 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 | 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 is a combination of #12920 and #13754. Prior to these changes,
following a redirect when searching indexes would bypass our
authentication middleware. This PR updates uv to support propagating
credentials through our middleware on same-origin redirects and to
support netrc credentials for both same- and cross-origin redirects. It
does not handle the case described in #11097 where the redirect location
itself includes credentials (e.g.,
`https://user:pass@redirect-location.com`). That will be addressed in
follow-up work.

This includes unit tests for the new redirect logic and integration
tests for credential propagation. The automated external registries test
is also passing for AWS CodeArtifact, Azure Artifacts, GCP Artifact
Registry, JFrog Artifactory, GitLab, Cloudsmith, and Gemfury.
2025-06-20 09:21:32 +02:00
Jack O'Connor
cc8d5a9215
handle an existing shebang in uv init --script (#14141)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 | 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
Closes https://github.com/astral-sh/uv/issues/14085.
2025-06-19 14:47:22 -07:00
Jack O'Connor
c3e4b63806 document the way member sources shadow workspace sources
Some checks are pending
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (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 | 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 | graalpy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
Closes https://github.com/astral-sh/uv/issues/14093.
2025-06-18 15:31:23 -07:00
Zanie Blue
e1046242e7
Fix Docker attestations (#14133)
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 | 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
These regressed in #14088 and were found during my test publish from a
fork.
2025-06-18 18:46:30 +00:00
Zanie Blue
1fc65a1d9d
Publish to DockerHub (#14088)
The primary motivation here is to avoid confusion with non-official
repositories, e.g., https://github.com/astral-sh/uv/issues/13958 which
could lead to attacks against our users.

Resolves

- https://github.com/astral-sh/uv/issues/12679
- #8699
2025-06-18 11:30:37 -05:00
Zanie Blue
75d4cd30d6
Use Depot for Windows cargo test (#14122)
Replaces https://github.com/astral-sh/uv/pull/12320

Switches to Depot for the large Windows runner we use for `cargo test`.

The runtime goes from 8m 20s -> 6m 44s (total) and 7m 18s -> 4m 41s
(test run) which are 20% and 35% speedups respectively.

A few things got marginally slower, like Python installs went from 11s
-> 38s, the Rust cache went from 15s -> 30s, and drive setup went from
7s -> 20s.
2025-06-18 09:55:09 -05:00
John Mumm
611a13c841
Fix benchmark compilation failure: cannot find attribute clap in this scope (#14128)
[Two benchmark
jobs](4433771099)
were failing with `error: cannot find attribute clap in this scope`
based on #14120. This updates the recently added `#[clap(name = rocm...`
lines to use `cfg_attr(feature = "clap",`.
2025-06-18 16:30:12 +02:00
konsti
ee0ba65eb2
Unify test venv python command creation (#14117)
Refactoring in preparation for
https://github.com/astral-sh/uv/pull/14080
2025-06-18 15:06:09 +02:00
Charlie Marsh
4d9c9a1e76
Add ROCm backends to --torch-backend (#14120)
Some checks are pending
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 | 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 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 | 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 | amazonlinux (push) Blocked by required conditions
We don't yet support automatic detection, but this at least allows
explicit selection (e.g., `uv pip install --torch-backend rocm5.3`).

Closes #14087.
2025-06-18 07:35:05 -04:00
Aaron Ang
0cac73dc1f
Warn on empty index directory (#13940)
Close #13922

## Summary

Add a warning if the directory given by the `--index` argument is empty.

## Test Plan

Added test case `add_index_empty_directory` in `edit.rs`
2025-06-18 10:48:21 +02:00
konsti
499c8aa808
Fix PyPI publish test script (#14116)
The script stumbled over a newline introduced in
https://github.com/pypi/warehouse/pull/18266 (which is valid).

Also fixed: Don't read versions for the same package from other indexes.
We were using `project_name` here instead of `target`, while using the
latter and only reading from a single index simplifies the code too.
2025-06-18 09:51:53 +02:00
John Mumm
2fc922144a
Add script for testing uv against different registries (#13615)
This PR provides a script that uses environment variables to determine
which registries to test. This script is being used to run automated
registry tests in CI for AWS, Azure, GCP, Artifactory, GitLab,
Cloudsmith, and Gemfury.

You must configure the following required env vars for each registry:
```
    UV_TEST_<registry_name>_URL            URL for the registry
    UV_TEST_<registry_name>_TOKEN       authentication token
    UV_TEST_<registry_name>_PKG          private package to install
```

The username defaults to "\_\_token\_\_" but can be optionally set with:
```
    UV_TEST_<registry_name>_USERNAME
```

For each configured registry, the test will attempt to install the
specified package. Some registries can fall back to PyPI internally, so
it's important to choose a package that only exists in the registry you
are testing.

Currently, a successful test means that it finds the line “ +
<package_name>” in the output. This is because in its current form we
don’t know ahead of time what package it is and hence what the exact
expected output would be. The advantage if that anyone can run this
locally, though they would have to have access to the registries they
want to test.

You can also use the `--use-op` command line argument to derive these
test env vars from a 1Password vault (default is "RegistryTests" but can
be configured with `--op-vault`). It will look at all items in the vault
with names following the pattern `UV_TEST_<registry_name>` and will
derive the env vars as follows:

```
    `UV_TEST_<registry_name>_USERNAME` from the `username` field
    `UV_TEST_<registry_name>_TOKEN` from the `password` field
    `UV_TEST_<registry_name>_URL` from a field with the label `url`
    `UV_TEST_<registry_name>_PKG` from a field with the label `pkg`
```
2025-06-18 09:43:45 +02:00
Zanie Blue
47c522f9be
Serialize Python requests for tools as canonicalized strings (#14109)
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 cache | macos aarch64 (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 | 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
When working on support for reading global Python pins in tool
operations, I noticed that we weren't using the canonicalized Python
request in receipts — we were using the raw string provided by the user.
Since we'll need to compare these values, we should be using the
canonicalized string.

The `Tool` and `ToolReceipt` types have been updated to hold a
`PythonRequest` instead of a `String`, and `Serialize` was implemented
for `PythonRequest` so canonicalization can happen at the edge instead
of being the caller's responsibility.
2025-06-17 17:45:11 -05:00
Charlie Marsh
6c096246d8
Remove preview label from --torch-backend (#14119)
This is now used in enough places that I'm comfortable committing to
maintaining it under our versioning policy.

Closes #14091.
2025-06-17 16:49:00 -04:00
Zanie Blue
8808e67cff
Add a docker-plan step to consolidate push and tag logic (#14083)
The dist plan parsing is pretty hard to understand, and I want to add
more images, e.g., for DockerHub in #14088. As a simplifying
precursor... move the dist plan processing into a dedicated step.
2025-06-17 15:04:39 -05:00
Zanie Blue
c25c800367
Fix Ruff linting (#14111)
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 | python on macos x86-64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (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 | 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
2025-06-17 17:28:23 +00:00
konsti
10e1d17cfc
Don't use walrus operator in interpreter query script (#14108)
Fix `uv run -p 3.7` by not using a walrus operator. Python 3.7 isn't
really supported anymore, but there's no reason to break interpreter
discovery for it.
2025-06-17 12:18:08 -05:00
Andrew Gallant
3d4f0c934e
Fix handling of changes to requires-python (#14076)
When using `uv lock --upgrade-package=python` after changing
`requires-python`, it was possible to get into a state where the fork
markers produced corresponded to the empty set. This in turn resulted in
an empty lock file.

There was already some infrastructure in place that I think was perhaps
intended to handle this. In particular, `Lock::check_marker_coverage`
checks whether the fork markers have some overlap with the supported
environments (including the `requires-python`). But there were two
problems with this.

First is that in lock validation, this marker coverage check came
_after_ a path that returned `Preferable` (meaning that the fork markers
should be kept) when `--upgrade-package` was used. Second is that the
marker coverage check used the `requires-python` in the lock file and
_not_ the `requires-python` in the now updated `pyproject.toml`.

We attempt to solve this conundrum by slightly re-arranging lock file
validation and by explicitly checking whether the *new*
`requires-python` is disjoint from the fork markers in the lock file. If
it is, then we return `Versions` from lock file validation (indicating
that the fork markers should be dropped).

Fixes #13951
2025-06-17 11:50:05 -04:00
FishAlchemist
d653fbb133
doc: Sync PyTorch integration index for CUDA and ROCm versions from PyTorch website. (#14100)
## Summary
Just to sync the documentation with PyTorch's officially recommended
installation method.

![image](https://github.com/user-attachments/assets/7be0aea6-b51b-4083-acae-fbe8aa79c363)
**Change:**
* CUDA 12.1 to CUDA 12.6
* CUDA 12.4 to CUDA 12.8
* ROCm 6.2 to ROCm 6.3
## Test Plan
Run doc server in local.
Result:
<details><summary>CUDA 12.6</summary>
<p>


![image](https://github.com/user-attachments/assets/962a1058-3922-4709-a57f-200939d0a397)

![image](https://github.com/user-attachments/assets/0dae693f-2dc1-4d3e-9186-d26aa84c7d73)

</p>
</details> 
<details><summary>CUDA 12.8</summary>
<p>


![image](https://github.com/user-attachments/assets/dc12d09b-f8f2-41d3-b185-cb1e4e8b062b)

![image](https://github.com/user-attachments/assets/1b5490e3-6265-4bad-8af2-eab0a207adab)

</p>
</details> 
<details><summary>ROCm6</summary>
<p>


![image](https://github.com/user-attachments/assets/3b17a24f-3210-4a99-a81b-f8f2f5578b73)

![image](https://github.com/user-attachments/assets/c7baae55-14e5-45d0-94a0-164ab31bbffc)

</p>
</details>
2025-06-17 09:55:03 -04:00
John Mumm
e02cd74e64
Turn off clippy::struct_excessive_bools rule (#14102)
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 | 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
We always ignore the `clippy::struct_excessive_bools` rule and formerly
annotated this at the function level. This PR specifies the allow in
`workspace.lints.clippy` in `Cargo.toml`.
2025-06-17 12:18:54 +02:00
Zanie Blue
cf67d9c633
Clear XDG_DATA_HOME during test runs (#14075)
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 | 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
2025-06-16 15:01:17 -05:00
Kyle Galbraith
d73d3e8b53
Refactor Docker image builds to use Depot (#13459)
Some checks are pending
CI / check cache | ubuntu (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 | 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
## Summary

Simplify the Docker image build process to leverage Depot container
builders for faster layer caching and native multi-platform image
builds. The combo of the two removes the need to save cache to
registries and do complex merge operations across GHA runners to get a
multi-platform image.

## Test Plan

UV team will need to add a trust relationship in Depot so that the
container builds can authenticate and run. This can be done following
these docs:
https://depot.dev/docs/cli/authentication#adding-a-trust-relationship-for-github-actions.

Once that is done, this should just work as before, but without all of
the extra work around manifests. We should double that all of the
tagging still makes sense for you all, as some bits of that were
unclear.

Additional context in this draft PR:
https://github.com/astral-sh/uv/pull/9156

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-16 13:32:35 -05:00
konsti
423cfaabf5
Show backtraces for CI crashes (#14081)
I only just realized that we can get backtraces for crashes with
`RUST_BACKTRACE: 1`, even non-panics
(https://github.com/astral-sh/uv/pull/14079). This is much better than
trying to analyze crash dumps.
2025-06-16 17:10:21 +00:00
Andrew Gallant
5c1ebf902b
Add rustfmt.toml (#14072)
We've gotten away without this file for a while. In particular, we
explicitly use its default settings.

However, this is occasionally problematic in certain contexts where
`rustfmt` is invoked directly. Or in contexts where the Rust Edition is
otherwise not specified. At least, this happens when using the Rust vim
plugin. When an edition isn't explicitly specified, it defaults back to
the 2015 edition.

I think that there aren't a lot of rustfmt changes, and so we've been
able to get away with this for a while. But it looks like something in
the 2024 edition changes how imports are ordered. So to make it explicit
that we want to use the 2024 edition of rustfmt, we opt into it.

This is analogous to a change made to the Ruff repository somewhat
recently: https://github.com/astral-sh/ruff/pull/18197
2025-06-16 10:05:56 -04:00
konsti
cd71ad1672
Show retries for HTTP status code errors (#13897)
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 | 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
Using a companion change in the middleware
(https://github.com/TrueLayer/reqwest-middleware/pull/235, forked&tagged
pending review), we can check and show retries for HTTP status core
errors, to consistently report retries again.

We fix two cases:
* Show retries for status code errors for cache client requests
* Show retries for status code errors for Python download requests

Not handled:
* Show previous retries when a distribution download fails mid-streaming
* Perform retries when a distribution download fails mid-streaming
* Show previous retries when a Python download fails mid-streaming
* Perform retries when a Python download fails mid-streaming
2025-06-16 10:14:00 +00:00
renovate[bot]
7c90c5be02
Update conda-incubator/setup-miniconda action to v3.2.0 (#14061)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[conda-incubator/setup-miniconda](https://redirect.github.com/conda-incubator/setup-miniconda)
| action | minor | `v3.1.1` -> `v3.2.0` |

---

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

---

### Release Notes

<details>
<summary>conda-incubator/setup-miniconda
(conda-incubator/setup-miniconda)</summary>

###
[`v3.2.0`](https://redirect.github.com/conda-incubator/setup-miniconda/blob/HEAD/CHANGELOG.md#v320-2025-06-04)

[Compare
Source](https://redirect.github.com/conda-incubator/setup-miniconda/compare/v3.1.1...v3.2.0)

##### Fixes

- Check all `.condarc` files when removing `defaults` by
[@&#8203;marcoesters](https://redirect.github.com/marcoesters) in

[https://github.com/conda-incubator/setup-miniconda/pull/398](https://redirect.github.com/conda-incubator/setup-miniconda/pull/398)/398
- Add version normalization for minicondaVersion in input validation by
[@&#8203;jezdez](https://redirect.github.com/jezdez)

[https://github.com/conda-incubator/setup-miniconda/pull/397](https://redirect.github.com/conda-incubator/setup-miniconda/pull/397)/397
- Workaround for auto_activate_base deprecation by
[@&#8203;jaimergp](https://redirect.github.com/jaimergp) in

[https://github.com/conda-incubator/setup-miniconda/pull/402](https://redirect.github.com/conda-incubator/setup-miniconda/pull/402)/402

##### Tasks and Maintenance

- Bump conda-incubator/setup-miniconda from 3.1.0 to 3.1.1 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in

[https://github.com/conda-incubator/setup-miniconda/pull/391](https://redirect.github.com/conda-incubator/setup-miniconda/pull/391)/391
- Bump undici from 5.28.4 to 5.28.5 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in

[https://github.com/conda-incubator/setup-miniconda/pull/390](https://redirect.github.com/conda-incubator/setup-miniconda/pull/390)/390
- Bump semver and
[@&#8203;types/semver](https://redirect.github.com/types/semver) by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in

[https://github.com/conda-incubator/setup-miniconda/pull/399](https://redirect.github.com/conda-incubator/setup-miniconda/pull/399)/399

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 11:53:56 +02:00
renovate[bot]
77ec5f9b17
Update actions/setup-python action to v5.6.0 (#14060)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[actions/setup-python](https://redirect.github.com/actions/setup-python)
| action | minor | `v5` -> `v5.6.0` |

---

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

---

### Release Notes

<details>
<summary>actions/setup-python (actions/setup-python)</summary>

###
[`v5.6.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.6.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.5.0...v5.6.0)

##### What's Changed

- Workflow updates related to Ubuntu 20.04 by
[@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y) in
[https://github.com/actions/setup-python/pull/1065](https://redirect.github.com/actions/setup-python/pull/1065)
- Fix for Candidate Not Iterable Error by
[@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y) in
[https://github.com/actions/setup-python/pull/1082](https://redirect.github.com/actions/setup-python/pull/1082)
- Upgrade semver and
[@&#8203;types/semver](https://redirect.github.com/types/semver) by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1091](https://redirect.github.com/actions/setup-python/pull/1091)
- Upgrade prettier from 2.8.8 to 3.5.3 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1046](https://redirect.github.com/actions/setup-python/pull/1046)
- Upgrade ts-jest from 29.1.2 to 29.3.2 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1081](https://redirect.github.com/actions/setup-python/pull/1081)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.6.0

###
[`v5.5.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.5.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.4.0...v5.5.0)

##### What's Changed

##### Enhancements:

- Support free threaded Python versions like '3.13t' by
[@&#8203;colesbury](https://redirect.github.com/colesbury) in
[https://github.com/actions/setup-python/pull/973](https://redirect.github.com/actions/setup-python/pull/973)
- Enhance Workflows: Include ubuntu-arm runners, Add e2e Testing for
free threaded and Upgrade
[@&#8203;action/cache](https://redirect.github.com/action/cache) from
4.0.0 to 4.0.3 by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/1056](https://redirect.github.com/actions/setup-python/pull/1056)
- Add support for .tool-versions file in setup-python by
[@&#8203;mahabaleshwars](https://redirect.github.com/mahabaleshwars) in
[https://github.com/actions/setup-python/pull/1043](https://redirect.github.com/actions/setup-python/pull/1043)

##### Bug fixes:

- Fix architecture for pypy on Linux ARM64 by
[@&#8203;mayeut](https://redirect.github.com/mayeut) in
[https://github.com/actions/setup-python/pull/1011](https://redirect.github.com/actions/setup-python/pull/1011)
This update maps arm64 to aarch64 for Linux ARM64 PyPy installations.

##### Dependency updates:

- Upgrade [@&#8203;vercel/ncc](https://redirect.github.com/vercel/ncc)
from 0.38.1 to 0.38.3 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1016](https://redirect.github.com/actions/setup-python/pull/1016)
- Upgrade
[@&#8203;actions/glob](https://redirect.github.com/actions/glob) from
0.4.0 to 0.5.0 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1015](https://redirect.github.com/actions/setup-python/pull/1015)

##### New Contributors

- [@&#8203;colesbury](https://redirect.github.com/colesbury) made their
first contribution in
[https://github.com/actions/setup-python/pull/973](https://redirect.github.com/actions/setup-python/pull/973)
- [@&#8203;mahabaleshwars](https://redirect.github.com/mahabaleshwars)
made their first contribution in
[https://github.com/actions/setup-python/pull/1043](https://redirect.github.com/actions/setup-python/pull/1043)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.5.0

###
[`v5.4.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.4.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.3.0...v5.4.0)

##### What's Changed

##### Enhancements:

- Update cache error message by
[@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y) in
[https://github.com/actions/setup-python/pull/968](https://redirect.github.com/actions/setup-python/pull/968)
- Enhance Workflows: Add Ubuntu-24, Remove Python 3.8 by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/985](https://redirect.github.com/actions/setup-python/pull/985)
- Configure Dependabot settings by
[@&#8203;HarithaVattikuti](https://redirect.github.com/HarithaVattikuti)
in
[https://github.com/actions/setup-python/pull/1008](https://redirect.github.com/actions/setup-python/pull/1008)

##### Documentation changes:

- Readme update - recommended permissions by
[@&#8203;benwells](https://redirect.github.com/benwells) in
[https://github.com/actions/setup-python/pull/1009](https://redirect.github.com/actions/setup-python/pull/1009)
- Improve Advanced Usage examples by
[@&#8203;lrq3000](https://redirect.github.com/lrq3000) in
[https://github.com/actions/setup-python/pull/645](https://redirect.github.com/actions/setup-python/pull/645)

##### Dependency updates:

- Upgrade `undici` from 5.28.4 to 5.28.5 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1012](https://redirect.github.com/actions/setup-python/pull/1012)
- Upgrade `urllib3` from 1.25.9 to 1.26.19 in /**tests**/data by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/895](https://redirect.github.com/actions/setup-python/pull/895)
- Upgrade `actions/publish-immutable-action` from 0.0.3 to 0.0.4 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1014](https://redirect.github.com/actions/setup-python/pull/1014)
- Upgrade `@actions/http-client` from 2.2.1 to 2.2.3 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1020](https://redirect.github.com/actions/setup-python/pull/1020)
- Upgrade `requests` from 2.24.0 to 2.32.2 in /**tests**/data by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/1019](https://redirect.github.com/actions/setup-python/pull/1019)
- Upgrade `@actions/cache` to `^4.0.0` by
[@&#8203;priyagupta108](https://redirect.github.com/priyagupta108) in
[https://github.com/actions/setup-python/pull/1007](https://redirect.github.com/actions/setup-python/pull/1007)

##### New Contributors

- [@&#8203;benwells](https://redirect.github.com/benwells) made their
first contribution in
[https://github.com/actions/setup-python/pull/1009](https://redirect.github.com/actions/setup-python/pull/1009)
-
[@&#8203;HarithaVattikuti](https://redirect.github.com/HarithaVattikuti)
made their first contribution in
[https://github.com/actions/setup-python/pull/1008](https://redirect.github.com/actions/setup-python/pull/1008)
- [@&#8203;lrq3000](https://redirect.github.com/lrq3000) made their
first contribution in
[https://github.com/actions/setup-python/pull/645](https://redirect.github.com/actions/setup-python/pull/645)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.4.0

###
[`v5.3.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.3.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.2.0...v5.3.0)

#### What's Changed

- Add workflow file for publishing releases to immutable action package
by [@&#8203;Jcambass](https://redirect.github.com/Jcambass) in
[https://github.com/actions/setup-python/pull/941](https://redirect.github.com/actions/setup-python/pull/941)
- Upgrade IA publish by
[@&#8203;Jcambass](https://redirect.github.com/Jcambass) in
[https://github.com/actions/setup-python/pull/943](https://redirect.github.com/actions/setup-python/pull/943)

##### Bug Fixes:

- Normalise Line Endings to Ensure Cross-Platform Consistency by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/938](https://redirect.github.com/actions/setup-python/pull/938)
- Revise `isGhes` logic by
[@&#8203;jww3](https://redirect.github.com/jww3) in
[https://github.com/actions/setup-python/pull/963](https://redirect.github.com/actions/setup-python/pull/963)
- Bump pillow from 7.2 to 10.2.0 by
[@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y) in
[https://github.com/actions/setup-python/pull/956](https://redirect.github.com/actions/setup-python/pull/956)

##### Enhancements:

- Enhance workflows and documentation updates by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/965](https://redirect.github.com/actions/setup-python/pull/965)
- Bump default versions to latest by
[@&#8203;jeffwidman](https://redirect.github.com/jeffwidman) in
[https://github.com/actions/setup-python/pull/905](https://redirect.github.com/actions/setup-python/pull/905)

#### New Contributors

- [@&#8203;Jcambass](https://redirect.github.com/Jcambass) made their
first contribution in
[https://github.com/actions/setup-python/pull/941](https://redirect.github.com/actions/setup-python/pull/941)
- [@&#8203;jww3](https://redirect.github.com/jww3) made their first
contribution in
[https://github.com/actions/setup-python/pull/963](https://redirect.github.com/actions/setup-python/pull/963)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.3.0

###
[`v5.2.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.2.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.1.1...v5.2.0)

#### What's Changed

##### Bug fixes:

- Add `.zip` extension to Windows package downloads for `Expand-Archive`
Compatibility by
[@&#8203;priyagupta108](https://redirect.github.com/priyagupta108) in
[https://github.com/actions/setup-python/pull/916](https://redirect.github.com/actions/setup-python/pull/916)
This addresses compatibility issues on Windows self-hosted runners by
ensuring that the filenames for Python and PyPy package downloads
explicitly include the .zip extension, allowing the Expand-Archive
command to function correctly.
- Add arch to cache key by
[@&#8203;Zxilly](https://redirect.github.com/Zxilly) in
[https://github.com/actions/setup-python/pull/896](https://redirect.github.com/actions/setup-python/pull/896)
This addresses issues with caching by adding the architecture (arch) to
the cache key, ensuring that cache keys are accurate to prevent
conflicts.
Note: This change may break previous cache keys as they will no longer
be compatible with the new format.

##### Documentation changes:

- Fix display of emojis in contributors doc by
[@&#8203;sciencewhiz](https://redirect.github.com/sciencewhiz) in
[https://github.com/actions/setup-python/pull/899](https://redirect.github.com/actions/setup-python/pull/899)
- Documentation update for caching poetry dependencies by
[@&#8203;gowridurgad](https://redirect.github.com/gowridurgad) in
[https://github.com/actions/setup-python/pull/908](https://redirect.github.com/actions/setup-python/pull/908)

##### Dependency updates:

- Bump [@&#8203;iarna/toml](https://redirect.github.com/iarna/toml)
version from 2.2.5 to 3.0.0 by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/912](https://redirect.github.com/actions/setup-python/pull/912)
- Bump pyinstaller from 3.6 to 5.13.1 by
[@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y) in
[https://github.com/actions/setup-python/pull/923](https://redirect.github.com/actions/setup-python/pull/923)

#### New Contributors

- [@&#8203;sciencewhiz](https://redirect.github.com/sciencewhiz) made
their first contribution in
[https://github.com/actions/setup-python/pull/899](https://redirect.github.com/actions/setup-python/pull/899)
- [@&#8203;priyagupta108](https://redirect.github.com/priyagupta108)
made their first contribution in
[https://github.com/actions/setup-python/pull/916](https://redirect.github.com/actions/setup-python/pull/916)
- [@&#8203;Zxilly](https://redirect.github.com/Zxilly) made their first
contribution in
[https://github.com/actions/setup-python/pull/896](https://redirect.github.com/actions/setup-python/pull/896)
- [@&#8203;aparnajyothi-y](https://redirect.github.com/aparnajyothi-y)
made their first contribution in
[https://github.com/actions/setup-python/pull/923](https://redirect.github.com/actions/setup-python/pull/923)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.2.0

###
[`v5.1.1`](https://redirect.github.com/actions/setup-python/releases/tag/v5.1.1)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5.1.0...v5.1.1)

#### What's Changed

##### Bug fixes:

- fix(ci): update all failing workflows by
[@&#8203;mayeut](https://redirect.github.com/mayeut) in
[https://github.com/actions/setup-python/pull/863](https://redirect.github.com/actions/setup-python/pull/863)
This update ensures compatibility and optimal performance of workflows
on the latest macOS version.

##### Documentation changes:

- Documentation update for cache by
[@&#8203;gowridurgad](https://redirect.github.com/gowridurgad) in
[https://github.com/actions/setup-python/pull/873](https://redirect.github.com/actions/setup-python/pull/873)

##### Dependency updates:

- Bump braces from 3.0.2 to 3.0.3 and undici from 5.28.3 to 5.28.4 by
[@&#8203;dependabot](https://redirect.github.com/dependabot) in
[https://github.com/actions/setup-python/pull/893](https://redirect.github.com/actions/setup-python/pull/893)

#### New Contributors

- [@&#8203;gowridurgad](https://redirect.github.com/gowridurgad) made
their first contribution in
[https://github.com/actions/setup-python/pull/873](https://redirect.github.com/actions/setup-python/pull/873)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5...v5.1.1

###
[`v5.1.0`](https://redirect.github.com/actions/setup-python/releases/tag/v5.1.0)

[Compare
Source](https://redirect.github.com/actions/setup-python/compare/v5...v5.1.0)

#### What's Changed

- Leveraging the raw API to retrieve the version-manifest, as it does
not impose a rate limit and hence facilitates unrestricted consumption
without the need for a token for Github Enterprise Servers by
[@&#8203;Shegox](https://redirect.github.com/Shegox) in
[https://github.com/actions/setup-python/pull/766](https://redirect.github.com/actions/setup-python/pull/766).
- Dependency updates by
[@&#8203;dependabot](https://redirect.github.com/dependabot) and
[@&#8203;HarithaVattikuti](https://redirect.github.com/HarithaVattikuti)
in
[https://github.com/actions/setup-python/pull/817](https://redirect.github.com/actions/setup-python/pull/817)
- Documentation changes for version in README by
[@&#8203;basnijholt](https://redirect.github.com/basnijholt) in
[https://github.com/actions/setup-python/pull/776](https://redirect.github.com/actions/setup-python/pull/776)
- Documentation changes for link in README by
[@&#8203;ukd1](https://redirect.github.com/ukd1) in
[https://github.com/actions/setup-python/pull/793](https://redirect.github.com/actions/setup-python/pull/793)
- Documentation changes for link in Advanced Usage by
[@&#8203;Jamim](https://redirect.github.com/Jamim) in
[https://github.com/actions/setup-python/pull/782](https://redirect.github.com/actions/setup-python/pull/782)
- Documentation changes for avoiding rate limit issues on GHES by
[@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali) in
[https://github.com/actions/setup-python/pull/835](https://redirect.github.com/actions/setup-python/pull/835)

#### New Contributors

- [@&#8203;basnijholt](https://redirect.github.com/basnijholt) made
their first contribution in
[https://github.com/actions/setup-python/pull/776](https://redirect.github.com/actions/setup-python/pull/776)
- [@&#8203;ukd1](https://redirect.github.com/ukd1) made their first
contribution in
[https://github.com/actions/setup-python/pull/793](https://redirect.github.com/actions/setup-python/pull/793)
- [@&#8203;Jamim](https://redirect.github.com/Jamim) made their first
contribution in
[https://github.com/actions/setup-python/pull/782](https://redirect.github.com/actions/setup-python/pull/782)
- [@&#8203;Shegox](https://redirect.github.com/Shegox) made their first
contribution in
[https://github.com/actions/setup-python/pull/766](https://redirect.github.com/actions/setup-python/pull/766)
- [@&#8203;priya-kinthali](https://redirect.github.com/priya-kinthali)
made their first contribution in
[https://github.com/actions/setup-python/pull/835](https://redirect.github.com/actions/setup-python/pull/835)

**Full Changelog**:
https://github.com/actions/setup-python/compare/v5.0.0...v5.1.0

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:48:19 +00:00
renovate[bot]
5beeda7cdc
Update acj/freebsd-firecracker-action action to v0.5.0 (#14057)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[acj/freebsd-firecracker-action](https://redirect.github.com/acj/freebsd-firecracker-action)
| action | minor | `v0.4.2` -> `v0.5.0` |

---

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

---

### Release Notes

<details>
<summary>acj/freebsd-firecracker-action
(acj/freebsd-firecracker-action)</summary>

###
[`v0.5.0`](https://redirect.github.com/acj/freebsd-firecracker-action/releases/tag/v0.5.0)

[Compare
Source](https://redirect.github.com/acj/freebsd-firecracker-action/compare/v0.4.2...v0.5.0)

Changes:

- Add `disk-size` option to control the size of the VM's disk and root
filesystem
- Retired obsolete workaround that disabled TCP segmentation offload
(TSO)

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 07:42:01 +00:00
renovate[bot]
9d0d612131
Update Rust crate which to v8 (#14066)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [which](https://redirect.github.com/harryfei/which-rs) |
workspace.dependencies | major | `7.0.0` -> `8.0.0` |

---

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

---

### Release Notes

<details>
<summary>harryfei/which-rs (which)</summary>

###
[`v8.0.0`](https://redirect.github.com/harryfei/which-rs/blob/HEAD/CHANGELOG.md#800)

[Compare
Source](https://redirect.github.com/harryfei/which-rs/compare/7.0.3...8.0.0)

- Add new `Sys` trait to allow abstracting over the underlying
filesystem. Particularly useful for `wasm32-unknown-unknown` targets.
Thanks [@&#8203;dsherret](https://redirect.github.com/dsherret) for this
contribution to which!
-   Add more debug level tracing for otherwise silent I/O errors.
- Call the `NonFatalHandler` in more places to catch previously ignored
I/O errors.
-   Remove use of the `either` dependency.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:37:38 +02:00
Frazer McLean
87827b6d82
Fix implied platform_machine marker for win_amd64 platform tag (#14041)
Some checks are pending
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
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 | windows registry (push) Blocked by required conditions
## Summary

Fixes #14040

## Test Plan

Added a test using required-environments
2025-06-15 22:37:40 -04:00
renovate[bot]
67c0f93e37
Update actions/checkout action to v4.2.2 (#14059) 2025-06-16 02:27:03 +00:00
renovate[bot]
ba6413f81f
Update actions/attest-build-provenance action to v2.4.0 (#14058) 2025-06-16 02:17:30 +00:00
renovate[bot]
a0ea520fe3
Update taiki-e/install-action action to v2.52.8 (#14056) 2025-06-16 02:05:57 +00:00
renovate[bot]
4d104dd004
Update Rust crate windows to v0.61.3 (#14055) 2025-06-16 02:05:34 +00:00
renovate[bot]
4b5da24fe0
Update Rust crate unicode-width to v0.2.1 (#14054) 2025-06-16 02:04:46 +00:00
renovate[bot]
f38e96bddd
Update actions/setup-python digest to a26af69 (#14045) 2025-06-15 21:47:33 -04:00
renovate[bot]
59f1b4bee4
Update Rust crate syn to v2.0.103 (#14051) 2025-06-15 21:41:54 -04:00
renovate[bot]
96cb90a1fd
Update Rust crate toml to v0.8.23 (#14052) 2025-06-15 21:41:31 -04:00
renovate[bot]
f0e0ad4d09
Update Rust crate smallvec to v1.15.1 (#14050) 2025-06-15 21:37:31 -04:00
renovate[bot]
3c00d6d7df
Update Rust crate memchr to v2.7.5 (#14048) 2025-06-15 21:37:22 -04:00
renovate[bot]
ce16a0fc9b
Update Rust crate boxcar to v0.2.13 (#14046) 2025-06-15 21:37:16 -04:00
renovate[bot]
15256722d8
Update Rust crate clap to v4.5.40 (#14047) 2025-06-15 21:36:58 -04:00
Aria Desires
ff9c2c35d7
Support reading dependency-groups from pyproject.tomls with no project (#13742)
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 | pyston (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 | 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
(or legacy tool.uv.workspace).

This cleaves out a dedicated SourcedDependencyGroups type based on
RequiresDist but with only the DependencyGroup handling implemented.
This allows `uv pip` to read `dependency-groups` from pyproject.tomls
that only have that table defined, per PEP 735, and as implemented by
`pip`.

However we want our implementation to respect various uv features when
they're available:

* `tool.uv.sources`
* `tool.uv.index`
* `tool.uv.dependency-groups.mygroup.requires-python` (#13735)

As such we want to opportunistically detect "as much as possible" while
doing as little as possible when things are missing. The issue with the
old RequiresDist path was that it fundamentally wanted to build the
package, and if `[project]` was missing it would try to desperately run
setuptools on the pyproject.toml to try to find metadata and make a hash
of things.

At the same time, the old code also put in a lot of effort to try to
pretend that `uv pip` dependency-groups worked like `uv`
dependency-groups with defaults and non-only semantics, only to separate
them back out again. By explicitly separating them out, we confidently
get the expected behaviour.

Note that dependency-group support is still included in RequiresDist, as
some `uv` paths still use it. It's unclear to me if those paths want
this same treatment -- for now I conclude no.

Fixes #13138
2025-06-13 22:16:48 +00:00
Aria Desires
5021840919
Add [tool.uv.dependency-groups].mygroup.requires-python (#13735)
This allows you to specify requires-python on individual dependency-groups,
with the intended usecase being "oh my dev-dependencies have a higher
requires-python than my actual project".

This includes a large driveby move of the RequiresPython type to
uv-distribution-types to allow us to generate the appropriate markers at
this point in the code. It also migrates RequiresPython from
pubgrub::Range to version_ranges::Ranges, and makes several pub(crate)
items pub, as it's no longer defined in uv_resolver.

Fixes #11606
2025-06-13 22:04:13 +00:00
Andrew Gallant
26db29caac
Update to jiff 0.2.15 (#14035)
This brings in https://github.com/BurntSushi/jiff/pull/385, which makes
cold resolves about 10% faster. Or, stated differently, as fast as they
were a few weeks ago before the perf regression introduced by
`jiff 0.2.14`.
2025-06-13 14:43:46 -04:00
konsti
d9b76b97c2
Remove unreachable pub function (#14032)
Not sure how this landed on main, but rustc complained.
2025-06-13 18:04:13 +00:00
Aria Desires
49b450109b
filter out riscv64 wheels before publishing to pypi (#14009)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 | 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
An alternative to #14006
2025-06-13 09:57:04 -04:00
konsti
da2eca4e2c
Make wiremock filter a default filter (#14024)
Make `127.0.0.1:<PORT>` -> ``[LOCALHOST]`` a general test filter, it
simplifies using wiremock and I'm not aware of any false positives.
2025-06-13 08:51:17 -05:00
Zanie Blue
881e17600f
Filter managed Python distributions by platform before querying when included in request (#13936)
In the case where we have platform information in a Python request, we
should filter managed Python distributions by it prior to querying them.

Closes https://github.com/astral-sh/uv/issues/13935

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
2025-06-13 08:50:44 -05:00
renovate[bot]
b95e66019d
Update Rust crate hyper-util to v0.1.14 (#13912)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [hyper-util](https://hyper.rs)
([source](https://redirect.github.com/hyperium/hyper-util)) |
dev-dependencies | patch | `0.1.12` -> `0.1.14` |

---

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

---

### Release Notes

<details>
<summary>hyperium/hyper-util (hyper-util)</summary>

###
[`v0.1.14`](https://redirect.github.com/hyperium/hyper-util/blob/HEAD/CHANGELOG.md#0114-2025-06-04)

[Compare
Source](https://redirect.github.com/hyperium/hyper-util/compare/v0.1.13...v0.1.14)

- Fix `HttpConnector` to defer address family order to resolver sort
order.
-   Fix `proxy::Matcher` to find HTTPS system proxies on Windows.

###
[`v0.1.13`](https://redirect.github.com/hyperium/hyper-util/blob/HEAD/CHANGELOG.md#0113-2025-05-27)

[Compare
Source](https://redirect.github.com/hyperium/hyper-util/compare/v0.1.12...v0.1.13)

- Fix `HttpConnector` to always prefer IPv6 addresses first, if happy
eyeballs is enabled.
- Fix `legacy::Client` to return better errors if available on the
connection.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC40MC4zIiwidXBkYXRlZEluVmVyIjoiNDAuNDAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-13 13:37:11 +02:00
konsti
e10881d49c
Add tests for IO Error retries (#13627)
Often, HTTP requests don't fail due to server errors, but from spurious
network errors such as connection resets. reqwest surfaces these as
`io::Error`, and we have to handle their retrying separately.

Companion PR: https://github.com/LukeMathWalker/wiremock-rs/pull/159
2025-06-13 09:57:45 +00:00
Zanie Blue
62ed17b230
Bump version to 0.7.13 (#14002)
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 | 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
2025-06-12 14:33:31 -05:00
konsti
7316bd01a3
Build backend: Support namespace packages (#13833)
Unlike regular packages, specifying all `__init__.py` directories for a
namespace package would be very verbose There is e.g.
https://github.com/python-poetry/poetry/tree/main/src/poetry, which has
18 modules, or https://github.com/googleapis/api-common-protos which is
inconsistently nested. For both the Google Cloud SDK, there are both
packages with a single module and those with complex structures, with
many having multiple modules due to versioning through `<module>_v1`
versioning. The Azure SDK seems to use one module per package (it's not
explicitly documented but seems to follow from the process in
https://azure.github.io/azure-sdk/python_design.html#azure-sdk-distribution-packages
and
ccb0e03a3d/doc/dev/packaging.md).

For simplicity with complex projects, we add a `namespace = true` switch
which disabled checking for an `__init__.py`. We only check that there's
no `<module_root>/<module_name>/__init__.py` and otherwise add the whole
`<module_root>/<module_name>` folder. This comes at the cost of
`namespace = true` effectively creating an opt-out from our usual checks
that allows creating an almost entirely arbitrary package.

For simple projects with only a single module, the module name can be
dotted to point to the target module, so the build still gets checked:

```toml
[tool.uv.build-backend]
module-name = "poetry.core"
```

## Alternatives

### Declare all packages

We could make `module-name` a list and allow or require declaring all
packages:

```toml
[tool.uv.build-backend]
module-name = ["cloud_sdk.service.storage", "cloud_sdk.service.storage_v1", "cloud_sdk.billing.storage"]
```

Or for Poetry:

```toml
[tool.uv.build-backend]
module-name = [
    "poetry.config",
    "poetry.console",
    "poetry.inspection",
    "poetry.installation",
    "poetry.json",
    "poetry.layouts",
    "poetry.masonry",
    "poetry.mixology",
    "poetry.packages",
    "poetry.plugins",
    "poetry.publishing",
    "poetry.puzzle",
    "poetry.pyproject",
    "poetry.repositories",
    "poetry.toml",
    "poetry.utils",
    "poetry.vcs",
    "poetry.version"
]
```

### Support multiple namespaces

We could also allow namespace packages with multiple root level module:

```toml
[tool.uv.build-backend]
module-name = ["cloud_sdk.my_ext", "local_sdk.my_ext"]
```

For lack of use cases, we delegate this to creating a workspace with one
package per module.

## Implementation

Due to the more complex options for the module name, I'm moving
verification on deserialization later, dropping the source span we'd get
from serde. We also don't show similarly named directories anymore.

---------

Co-authored-by: Andrew Gallant <andrew@astral.sh>
2025-06-12 17:23:58 +00:00
Zanie Blue
95ad8e5e82
Add 3.14 to the supported platform reference (#13990)
Some checks are pending
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | 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
2025-06-12 15:18:48 +00:00
Zanie Blue
e067118700
Add supported macOS version to the platform reference (#13993)
Closes https://github.com/astral-sh/uv/issues/13807
2025-06-12 15:16:24 +00:00
Zanie Blue
f82909ad68
Update platform support reference to include Python implementation list (#13991) 2025-06-12 10:14:42 -05:00
github-actions[bot]
d9c34259b3
Sync latest Python releases (#13996)
Automated update for Python releases.

---------

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-12 09:47:28 -05:00
Ahmed Ilyas
a1f9f28762
Do not allow uv add --group ... --script (#13997)
## Summary

Closes #13988 

## Test Plan

`cargo test`
2025-06-12 10:45:12 -04:00
Zanie Blue
806cc5cad9
Debug sync_dry_run flake by panicking with verbose output on failure (#13817)
Investigating #13744 

I tried reproducing here by running the test in a loop, but could not. I
presume it's an interaction with other tests.

This drops the snapshot, but I think it's worth it to try to examine the
flake?
2025-06-12 08:05:25 -05:00
Zanie Blue
87ab57e902
Update the CLI help and reference to include references to the Python bin directory (#13978)
Closes https://github.com/astral-sh/uv/issues/13977
2025-06-12 10:02:51 +00:00
konsti
b3d7f79770
Universal sync_required_environment_hint test (#13975)
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 | 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
Use the packse case `no-sdist-no-wheels-with-matching-platform` for a
platform independent `sync_required_environment_hint` test.

Fixes #13890
2025-06-11 22:47:40 -04:00
Charlie Marsh
81aebf921d
Add zstd and deflate to Accept-Encoding (#13982)
## Summary

We already pull in these dependencies, so it costs us nothing.
2025-06-11 22:42:47 -04:00
Zanie Blue
f530565323
Use TTY detection to determine if SIGINT forwarding is enabled (#13925)
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 / benchmarks | instrumented (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 | 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
Use TTY detection to determine when we should forward SIGINT instead of
counting signals, which can lead to various problems where multiple
SIGINTs are sent to a child after the first signal. Counting does not
make sense in interactive situations that do not exit on interrupt,
e.g., the Python REPL.

Closes https://github.com/astral-sh/uv/issues/13919
Closes https://github.com/astral-sh/uv/issues/12108
2025-06-11 13:28:34 +00:00
github-actions[bot]
357fc91c3c
Sync latest Python releases (#13956)
Some checks are pending
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
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 | windows registry (push) Blocked by required conditions
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-06-10 21:13:32 -05:00
Zanie Blue
4c877b7dc6
Fix generated file change (#13957)
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 | 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
Regressed in https://github.com/astral-sh/uv/pull/13620

ref failure at
4384658790
2025-06-10 22:03:01 +00:00
Zanie Blue
21986c3fc9
Bump timeout on Python download release fetch (#13955)
Failing with a 504 at
1556959077

Successful at
4384626025
2025-06-10 16:54:42 -05:00
Lan, Jian
90a7208a73
Fix and improve docs (#13620)
<!--
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

I follow the advices from the IDE spell checker and grammar checker, fix
some typos, and improve the docs.
2025-06-10 13:15:38 -05:00
Zanie Blue
f20a25f91f
Download versions in uv python pin if not found (#13946)
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 | 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
As another follow-up in the vein of
https://github.com/astral-sh/uv/pull/13944, I noticed `uv python pin`
doesn't download Python versions, which is a bit weird because we'll
warn it's not found.
2025-06-10 10:56:22 -05:00
Xeonacid
210b579188
build-binaries for riscv64 (#12688)
<!--
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? -->

Build riscv64 binary so it can get released in the GitHub Releases,
which is used by many high-level apps.

A copy-paste from linux-s390x, with only target and arch changed.

maturin-action added riscv64 support in v1.48.0, this PR also bumps it
to the latest version, v1.48.1.

## Test Plan

<!-- How was it tested? -->

Let CI test itself :P

Already tested in [my
fork](4004817230)
2025-06-10 11:18:28 -04:00
Zanie Blue
1b82a3ac99
Ignore Python discovery errors during uv python pin (#13944)
See https://github.com/astral-sh/uv/issues/13935#issuecomment-2957300516
where we fail to write a pin file because we encounter an unusable
interpreter. This is actually a special case where `MissingPython` is
not raised because we want to show why we failed to find a usable
interpreter, which is useful in commands where you _need_ an interpreter
to use, but here we don't actually need it. Here, we just log the
failure and move on.

Related https://github.com/astral-sh/uv/pull/13936
2025-06-10 09:52:23 -05:00
Charlie Marsh
28685633c0
Add an llms.txt to uv (#13929)
## Summary

The generated file looks like:

```
# uv

> uv is an extremely fast Python package and project manager, written in Rust.

You can use uv to install Python dependencies, run scripts, manage virtual environments,
build and publish packages, and even install Python itself. uv is capable of replacing
`pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`, and more.

uv includes both a pip-compatible CLI (prepend `uv` to a pip command, e.g., `uv pip install ruff`)
and a first-class project interface (e.g., `uv add ruff`) complete with lockfiles and
workspace support.


## Getting started

- [Features](https://docs.astral.sh/uv/getting-started/features/index.md)
- [First steps](https://docs.astral.sh/uv/getting-started/first-steps/index.md)
- [Installation](https://docs.astral.sh/uv/getting-started/installation/index.md)

## Guides

- [Installing Python](https://docs.astral.sh/uv/guides/install-python/index.md)
- [Publishing packages](https://docs.astral.sh/uv/guides/package/index.md)
- [Working on projects](https://docs.astral.sh/uv/guides/projects/index.md)
- [Running scripts](https://docs.astral.sh/uv/guides/scripts/index.md)
- [Using tools](https://docs.astral.sh/uv/guides/tools/index.md)

## Integrations

- [Alternative indexes](https://docs.astral.sh/uv/guides/integration/alternative-indexes/index.md)
- [AWS Lambda](https://docs.astral.sh/uv/guides/integration/aws-lambda/index.md)
- [Dependency bots](https://docs.astral.sh/uv/guides/integration/dependency-bots/index.md)
- [Docker](https://docs.astral.sh/uv/guides/integration/docker/index.md)
- [FastAPI](https://docs.astral.sh/uv/guides/integration/fastapi/index.md)
- [GitHub Actions](https://docs.astral.sh/uv/guides/integration/github/index.md)
- [GitLab CI/CD](https://docs.astral.sh/uv/guides/integration/gitlab/index.md)
- [Jupyter](https://docs.astral.sh/uv/guides/integration/jupyter/index.md)
- [marimo](https://docs.astral.sh/uv/guides/integration/marimo/index.md)
- [Pre-commit](https://docs.astral.sh/uv/guides/integration/pre-commit/index.md)
- [PyTorch](https://docs.astral.sh/uv/guides/integration/pytorch/index.md)

## Projects

- [Building distributions](https://docs.astral.sh/uv/concepts/projects/build/index.md)
- [Configuring projects](https://docs.astral.sh/uv/concepts/projects/config/index.md)
- [Managing dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/index.md)
- [Creating projects](https://docs.astral.sh/uv/concepts/projects/init/index.md)
- [Structure and files](https://docs.astral.sh/uv/concepts/projects/layout/index.md)
- [Running commands](https://docs.astral.sh/uv/concepts/projects/run/index.md)
- [Locking and syncing](https://docs.astral.sh/uv/concepts/projects/sync/index.md)
- [Using workspaces](https://docs.astral.sh/uv/concepts/projects/workspaces/index.md)

## Features

- [Authentication](https://docs.astral.sh/uv/concepts/authentication/index.md)
- [Build backend](https://docs.astral.sh/uv/concepts/build-backend/index.md)
- [Caching](https://docs.astral.sh/uv/concepts/cache/index.md)
- [Configuration files](https://docs.astral.sh/uv/concepts/configuration-files/index.md)
- [Package indexes](https://docs.astral.sh/uv/concepts/indexes/index.md)
- [Python versions](https://docs.astral.sh/uv/concepts/python-versions/index.md)
- [Resolution](https://docs.astral.sh/uv/concepts/resolution/index.md)
- [Tools](https://docs.astral.sh/uv/concepts/tools/index.md)

## The pip interface

- [Compatibility with pip](https://docs.astral.sh/uv/pip/compatibility/index.md)
- [Locking environments](https://docs.astral.sh/uv/pip/compile/index.md)
- [Declaring dependencies](https://docs.astral.sh/uv/pip/dependencies/index.md)
- [Using environments](https://docs.astral.sh/uv/pip/environments/index.md)
- [Inspecting environments](https://docs.astral.sh/uv/pip/inspection/index.md)
- [Managing packages](https://docs.astral.sh/uv/pip/packages/index.md)

## Reference

- [Commands](https://docs.astral.sh/uv/reference/cli/index.md)
- [Environment variables](https://docs.astral.sh/uv/reference/environment/index.md)
- [Installer](https://docs.astral.sh/uv/reference/installer/index.md)
- [Settings](https://docs.astral.sh/uv/reference/settings/index.md)
```

Closes #13901.
2025-06-10 07:46:49 -04:00
konsti
c54f131500
Add basic network error tests (#13585)
Add basic tests for error messages on retryable network errors.

This test mod is intended to grow to ensure that we handle retryable
errors correctly and that we show the appropriate error message if we
failed after retrying.

The starter tests show some common cases we've seen download errors in:
simple and find links indexes, file downloads and Python installs.

For `io::Error` fault injection to test the reqwest `Err` path besides
the HTTP status code `Ok` path, see
https://github.com/LukeMathWalker/wiremock-rs/issues/149.
2025-06-10 12:00:04 +02:00
Jack O'Connor
9129d2a9a3 avoid fetching an exact, cached commit, even if it isn't locked
Some checks are pending
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
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 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 | 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
Fixes #13513 and #12746.
2025-06-09 23:50:36 +00:00
Jack O'Connor
619132bd8a make GitOid strict about parsing exactly 40 hex characters 2025-06-09 23:50:36 +00:00
Jack O'Connor
9ff07c113f add a snapshot test for uv pip install with an exact Git commit 2025-06-09 23:50:36 +00:00
Jack O'Connor
dc455bfc26 add UV_NO_GITHUB_FAST_PATH 2025-06-09 23:50:36 +00:00
renovate[bot]
f5382c010b
Update acj/freebsd-firecracker-action action to v0.4.2 (#13906)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[acj/freebsd-firecracker-action](https://redirect.github.com/acj/freebsd-firecracker-action)
| action | patch | `v0.4.1` -> `v0.4.2` |

---

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

---

### Release Notes

<details>
<summary>acj/freebsd-firecracker-action
(acj/freebsd-firecracker-action)</summary>

###
[`v0.4.2`](https://redirect.github.com/acj/freebsd-firecracker-action/releases/tag/v0.4.2)

[Compare
Source](https://redirect.github.com/acj/freebsd-firecracker-action/compare/v0.4.1...v0.4.2)

[Firecracker
1.12.0](https://redirect.github.com/firecracker-microvm/firecracker/releases/tag/v1.12.0)
[FreeBSD 14.3-RELEASE](https://www.freebsd.org/releases/14.3R/relnotes/)

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC40MC4zIiwidXBkYXRlZEluVmVyIjoiNDAuNDAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 18:06:31 -05:00
renovate[bot]
e67dff85cc
Update Rust crate fs-err to v3.1.1 (#13910) 2025-06-09 14:29:12 -04:00
renovate[bot]
dd46985e27
Update Rust crate petgraph to v0.8.2 (#13913) 2025-06-09 14:28:51 -04:00
renovate[bot]
2940122e69
Update Rust crate hashbrown to v0.15.4 (#13911) 2025-06-09 14:28:39 -04:00
renovate[bot]
1f2bba9b3d
Update Rust crate flate2 to v1.1.2 (#13909) 2025-06-09 14:28:26 -04:00
renovate[bot]
64dacab913
Update pre-commit dependencies (#13907) 2025-06-09 14:28:16 -04:00
renovate[bot]
00b517dbd1
Update Rust crate anstream to v0.6.19 (#13908) 2025-06-09 14:28:09 -04:00
John Mumm
2a66349e96
Check if relative URL is valid directory before treating as index (#13917)
As per #13874, passing a relative URL like `test` to `--index` for `uv
add` causes unexpected behavior if the directory does not exist. The
non-existent index is effectively ignored and uv falls back to PyPI. If
a package is found there, the spurious index is then written to
`pyproject.toml`. This doesn't happen for `--default-index` since
resolution will fail without fallback to PyPI.

This PR adds a validation step for indexes provided on the command line.
If a directory does not exist, uv will fail with an error.

Closes #13874
2025-06-09 19:28:39 +02:00
Zanie Blue
619a0eafa1
Fix use of deprecated black_box function (#13926) 2025-06-09 16:57:27 +00:00
Zanie Blue
ea45acaf4f
Fix extra newline in changelog (#13918) 2025-06-09 11:48:59 -05:00
Karim Abou Zeid
5dae9ac5f2
Update referenced CUDA version in pytorch.md (#13899)
Some checks are pending
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (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.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 | 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
## Summary

torch 2.7 by default targets CUDA 12.6
2025-06-08 20:21:07 -04:00
Zanie Blue
dc3fd46472
Bump version to 0.7.12 (#13892)
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 | pyston (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 | 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
2025-06-06 19:42:06 +00:00
konsti
5b0133c0ec
Hint at tool.uv.required-environments (#13575)
For the case where there was no matching wheel on sync, we previously
added a note about which wheels are available vs. on which platform you
are on. We extend this error message to link directly towards
`tool.uv.required-environments`, which otherwise has a discovery
problem.

On Linux (Setting `tool.uv.required-environments` doesn't help here
either, but it's a clear example):

```
[project]
name = "debug"
version = "0.1.0"
requires-python = "==3.10.*"
dependencies = ["tensorflow-macos>=2.13.1"]
```

```
Resolved 41 packages in 24ms
error: Distribution `tensorflow-macos==2.16.2 @ registry+https://pypi.org/simple` can't be installed because it doesn't have a source distribution or wheel for the current platform

hint: You're on Linux (`manylinux_2_39_x86_64`), but there are no wheels for the current platform, consider configuring `tool.uv.required-environments`.
hint: `tensorflow-macos` (v2.16.2) only has wheels for the following platform: `macosx_12_0_arm64`.
```


![image](https://github.com/user-attachments/assets/b6b49461-10d6-4e1d-bc0a-5d35d98e33d0)

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-06 19:15:52 +00:00
konsti
7aefbe8dc5
Don't hint at versions removed by excluded-newer (#13884)
General small hint false positives that shows up as CI failure in our
snapshots.

Fixes #13867
2025-06-06 18:35:18 +00:00
konsti
0109af1aa5
Hint at tool.uv.environments on resolution error (#13455)
Users are not (yet) properly familiar with the concept of universal
resolution and its implication that we need to resolve for all possible
platforms and Python versions. Some projects only target a specific
platform or Python version, and users experience resolution errors due
to failures for other platforms. Indicated by the number of questions we
get about it, `tool.uv.environments` for restricting environments is not
well discoverable.

We add a special hint when resolution failed on a fork disjoint with the
current environment, hinting the user to constrain `requires-python` and
`tool.uv.environments` respectively.

The hint has false positives for cases where the resolution failed on a
different platform, but equally fails on the current platform, in cases
where the non-current fork was tried earlier. Given that conflicts can
be based on `requires-python`, afaik we can't parse whether the current
platform would also be affected from the derivation tree.

Two cases not covered by this are build errors as well as install errors
that need `tool.uv.required-environments`.
2025-06-06 14:17:52 +00:00
Yury Fedotov
8a88ab2c70
Minor internal README enhancement for Markdown list in PEP440 (#13880)
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 | 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
- Define all list elements using `-`: it used to be a mix of `*` and
`-`. `-` is what Prettier linter formats it to by default.
- Removed unnecessary blank line between 2 list elements. Other elements
were stitched together without blank lines in between.
- Only the first list element started in sentence case (capital letter
first) - I made all start like so.
2025-06-06 08:45:37 -05:00
konsti
bf96c60e3e
Lock during uv sync, uv add and uv remove to avoid race conditions (#13869)
Surprisingly, we weren't locking during `uv sync` so far, so running `uv
sync` in parallel could cause errors in filesystem races.

I've also added locks to `uv add` and `uv remove` which concurrently
modify `pyproject.toml`. These locks only apply after we determined the
interpreter, so they don't actually prevent computing the same thing
twice when running `uv add` in parallel.

All other subcommands that I checked were already locking (with no claim
to exhaustiveness)

Fixes #12751

# Test Plan

I don't have CI-sized reproducer for this.

```toml
[project]
name = "debug"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
  "boto3>=1.38.30",
  "fastapi>=0.115.12",
  "numba>=0.61.2",
  "polars>=1.30.0",
  "protobuf>=6.31.1",
  "pyarrow>=20.0.0",
  "pydantic>=2.11.5",
  "requests>=2.32.3",
  "urllib3>=2.4.0",
  "scikit-learn>=1.6.1",
  "jupyter>=1.1.1",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
```

```
rm -rf .venv && parallel -n0 "uv sync -q" ::: {1..10}
```
2025-06-06 14:16:40 +02:00
Micha Reiser
b865f76b78
Change GlobDirFilter fallback to true (#13882)
## Summary

I think `GlobDirFilter::match_directory` should return `true` if it
failed to construct a DFA
to force a full directory traversal. Returning `false` means that the
build backend excludes all files which
is unlikely what we want in that situation.
2025-06-06 14:07:34 +02:00
samypr100
a68fb53c4b
PEP 751 uv export supports --no-editable (#13852)
## Summary

When trying out `uv export --no-editable --format pylock.toml` the
exported contents would still retain `editable = true` regardless.

## Test Plan

Added additional test. Tested locally on few projects where I was
previously using `uv export --no-editable --format requirements.txt` to
ensure the output aligns.
2025-06-06 07:52:14 -04:00
Zanie Blue
7dd564d3d0
Improve python pin error messages (#13862)
Some checks are pending
CI / check system | python on macos aarch64 (push) Blocked by required conditions
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 | 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 | 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
Addresses https://github.com/astral-sh/uv/issues/13854
2025-06-05 21:48:34 +00:00
Jack O'Connor
94ed6f880f
update Git and GitHub Actions docs to mention gh auth login (#13850) 2025-06-05 20:44:59 +00:00
Zanie Blue
b1a50c33cf
Fix lock_requires_python test case (#13866)
Tracking https://github.com/astral-sh/uv/issues/13867
2025-06-05 17:27:52 +00:00
Zanie Blue
262ca73965
Remove the configuration section in favor of concepts / reference (#13842)
Extends https://github.com/astral-sh/uv/pull/13841 — I'll drop that
commit later after that pull request merges but it's small.

I find the split into a "Configuration" section awkward and don't think
it's helping us. Everything moved into the "Concepts" section, except
the "Environment variables" page which definitely belongs in the
reference and the "Installer" page which is fairly niche and seems
better in the reference.

Before / After


<img
src="https://github.com/user-attachments/assets/80d8304b-17da-4900-a5f4-c3ccac96fcc5"
width="400">
2025-06-05 17:09:49 +00:00
Zanie Blue
062b6ab743
Add uv python pin --rm to remove .python-version pins (#13860)
I realized it is non-trivial to delete the global Python version pin,
and that we were missing this simple functionality
2025-06-05 12:05:42 -05:00
Zanie Blue
789a246cf3
Move the pip interface documentation into the concepts section (#13841)
The motivation here being a reduction in the length of the navigation. I
don't think we did this in the first place because we didn't have the
capability to do another nested level, but now we're doing that for
Projects.
2025-06-05 11:53:27 -05:00
github-actions[bot]
cd89a592ea
Update tag for Python sysconfig metadata (#13851)
Automated update for Python releases.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-06-05 11:21:35 -05:00
Abhishek Upadhye
efd4652faa
List .gitignore in project init files (#13855)
Fixes https://github.com/astral-sh/uv/issues/13639

Just added a missing `.gitignore` file in the docs, so that there would
be no confusion for readers referring it.

Thank you!
2025-06-05 09:21:15 -05:00
Michał Górny
3a29bb0986
Switch sync_dry_run test to Python 3.9 (#13858)
Some checks are pending
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 | 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
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
## Summary

Switch the `sync_dry_run` test to use Python 3.9 instead of Python 3.8.
I didn't previously catch it since it was marked as `python_managed`.

## Test Plan

`cargo test --no-default-features --features git,pypi,python` without
Python 3.8 installed.
2025-06-05 08:15:00 -05:00
Michał Górny
042e8a448b
Make requirements_txt_ssh_git_username not write into homedir (#13857)
## Summary

Modify `requirements_txt_ssh_git_username` test to pass `-o
UserKnownHostsFile=/dev/null` to OpenSSH, in order to prevent it from
trying to write into the known-hosts in user's home directory. To add
insult to the injury, OpenSSH ignores `HOME` and writes into the actual
home when it is explicitly overridden for the purpose of testing.

## Test Plan

`cargo test --no-default-features --features=git,pypi,python` in an
environment where the user can't write to `pw_home` (but can to
`${HOME}`). Previously the test would fail:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Snapshot: requirements_txt_ssh_git_username
Source: crates/uv/tests/it/export.rs:1252
────────────────────────────────────────────────────────────────────────────────
Expression: snapshot
────────────────────────────────────────────────────────────────────────────────
-old snapshot
+new results
────────────┬───────────────────────────────────────────────────────────────────
    7     7 │   ├─▶ failed to clone into: [PATH]
    8     8 │   ├─▶ failed to fetch branch, tag, or commit `d780faf0ac91257d4d5a4f0c5a0e4509608c0071`
    9     9 │   ╰─▶ process didn't exit successfully: [GIT_COMMAND_ERROR]
   10    10 │       --- stderr
         11 │+      Could not create directory '/var/lib/portage/home/.ssh' (Permission denied).
         12 │+      Failed to add the host to the list of known hosts (/var/lib/portage/home/.ssh/known_hosts).
   11    13 │       Load key "[TEMP_DIR]/fake_deploy_key": [ERROR]
   12    14 │       git@github.com: Permission denied (publickey).
   13    15 │       fatal: Could not read from remote repository.
   14    16 │ 
────────────┴───────────────────────────────────────────────────────────────────
```

---------

Co-authored-by: konstin <konstin@mailbox.org>
2025-06-05 10:35:21 +00:00
Jack O'Connor
90a4416ab8
Bump version to 0.7.11 (#13844)
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 | 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
2025-06-04 12:35:56 -07:00
github-actions[bot]
8e8b7449dc
Sync latest Python releases (#13848)
20250604

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-06-04 19:07:04 +00:00
Zanie Blue
f168802ba4
Bump cargo-test-macos timeout to 15m (#13847)
Closes https://github.com/astral-sh/uv/issues/13846

15m is fine, we should definitely take action if it runs that long
normally though.
2025-06-04 18:24:40 +00:00
konsti
794b3ec750
Downgrade reqwest and hyper-util (#13835)
Workaround for https://github.com/astral-sh/uv/issues/13831, see also
https://github.com/hyperium/hyper/issues/3900
2025-06-04 18:48:53 +02:00
Aria Desires
d8636a4088
Prefer the binary's version when checking if it's up to date (#13840)
Fixes #13741
2025-06-04 11:32:59 -04:00
konsti
a748336a09
Follow-up #13814, git+ssh test case (#13839)
Follow-ups to review on #13814
2025-06-04 15:02:26 +00:00
konsti
e7c066cf16
Test case: Don't redact username git for SSH (#13814)
Some checks are pending
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
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 | 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 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 | 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
2025-06-04 09:57:24 +02:00
Zanie Blue
3ca8d074a4
Use "terminal driver" instead of "shell" in SIGINT docs (#13787)
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 | 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
Addressing the comment at
https://github.com/astral-sh/uv/issues/12108#issuecomment-2925703719
2025-06-03 22:07:03 +00:00
Jacob Woliver
f5c3601445
Better error message for version specifier with missing operator (#13803)
Some checks are pending
CI / benchmarks | instrumented (push) Blocked by required conditions
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 | 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
## Summary

When missing an operator for version parsing, it would give an error
that was hard to know how to fix if you were not familiar with version
specifiers / PEP-440:

```
Unexpected end of version specifier, expected operator
```

Now, it will attempt to provide a more useful hint if it can parse the
version from the remaining scanner:

```
Unexpected end of version specifier, expected operator (did you mean "==3.12"?)
```
## Test Plan

Unit tests in `version_specifier.rs` were added/updated for the
following cases:
- `test_parse_specifier_missing_operator_error`
- `test_parse_specifier_missing_operator_invalid_version_error`
- `test_invalid_word`
- `test_invalid_specifier`
- `error_message_version_specifiers_parse_error`

A test in `edit.rs` for failing to parse the `pyproject.toml` when using
`add` was also included to match the request in the original issue:
- `add_invalid_requires_python`

I didn't add cases where no version specifier is provided because it
seemed like it doesn't get to the point of parsing in that case, so it
should not happen.


## Reference

Fixes #13126

---------

Co-authored-by: Jacob Woliver <jacob@jmw.sh>
Co-authored-by: konstin <konstin@mailbox.org>
2025-06-03 19:18:19 +00:00
Hood Chatham
f9d3f24728
Add Pyodide support (#12731)
This includes some initial work on adding Pyodide support (issue
#12729). It is enough to get
```
uv pip compile -p /path/to/pyodide --extra-index-url file:/path/to/simple-index
```
to work which should already be quite useful.

## Test Plan

* added a unit test for `pyodide_platform`
* integration tested manually with:
```
cargo run pip install \
-p /home/rchatham/Documents/programming/tmp/pyodide-venv-test/.pyodide-xbuildenv-0.29.3/0.27.4/xbuildenv/pyodide-root/dist/python \
--extra-index-url file:/home/rchatham/Documents/programming/tmp/pyodide-venv-test/.pyodide-xbuildenv-0.29.3/0.27.4/xbuildenv/pyodide-root/package_index \
--index-strategy unsafe-best-match --target blah --no-build \
numpy pydantic
```

---------

Co-authored-by: konsti <konstin@mailbox.org>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-06-03 12:01:26 -05:00
Zanie Blue
37e22e4da6
Remove python-managed marker from sync_dry_run test (#13816)
Not sure why this is present, it does not seem to use a managed
interpreter
2025-06-03 11:08:09 -05:00
Zanie Blue
1e5120e15c
Bump version to 0.7.10 (#13821) 2025-06-03 11:07:21 -05:00
Zanie Blue
f429d99b6c
Disable OpenSUSE system test for now (#13818)
ref #13811
2025-06-03 14:53:09 +00:00
John Mumm
90aefe4a4a
Display ssh git username in Debug implementation (#13806)
This updates the `Debug` implementation of `DisplaySafeUrl` to display
the git username in a case like `git+ssh://git@github.com/org/repo`. It
also factors out the git username check into a shared function and adds
related unit tests to `DisplaySafeUrl`.
2025-06-03 14:52:51 +00:00
Zanie Blue
a96e766b55
Retain credentials for direct URLs in uv export (#13809)
Reverts unintended breaking change from #13560 

Test case from https://github.com/astral-sh/uv/pull/13808
2025-06-03 14:23:07 +00:00
konsti
63ba5e9f9e
Add data locations to logging (#13797)
`trace!`-log the locations of data directories used by a wheel. These
paths are queried from sysconfig, i.e. they are mostly Python
interpreter defined instead of being computed by uv.
2025-06-03 09:22:18 -05:00
konsti
eb9ad6c8c0
Don't redact username git for SSH (#13799)
Fixes #13795 specifically by not redacting the username convention `git`
for SSH URLs, though we should never write stars in `uv export`
generally (#13791).
2025-06-03 09:18:18 -05:00
Zanie Blue
99a4b78af2
Add comment to lock_redact_url_sources indicating that we do not redact the credentials (#13813)
This was previously present, but got removed at some point.


https://github.com/astral-sh/uv/pull/8307/files#diff-82edd36151736f44055f699a34c8b19a63ffc4cf3c86bf5fb34d69f8ac88a957R6544
2025-06-03 14:15:46 +00:00
Zanie Blue
c8448815ef
Add uv export test cases for PEP 751 format with credentials (#13810)
Same as the following, but for `pylock.toml` instead of
`requirements.txt`

- #13808
- #13792
2025-06-03 09:11:53 -05:00
Zanie Blue
4cdac77fe9
Add test case for HTTPS credentials on direct URL in uv export (#13808)
Related to 

- #13799 
- #13792
2025-06-03 14:11:13 +00:00
konsti
fd48b8bb78
Update acj/freebsd-firecracker-action to v0.4.1 (#13804)
This should hopefully fix the flakes we're seeing.

Fixes #13746, hopefully.
2025-06-03 15:12:03 +02:00
Zanie Blue
98c708149a
Add uv export test case with credentials in pyproject.toml (#13792)
Testing reported case in https://github.com/astral-sh/uv/issues/13791

I cherry-picked this commit onto 0.7.0, and saw no change.
2025-06-03 07:47:05 -05:00
konsti
4368c403fe
Downgrade firecracker action to v0.3 (#13786)
Some checks are pending
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 opensuse (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 | 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
See https://github.com/acj/freebsd-firecracker-action/issues/3
2025-06-02 13:25:12 -05:00
samypr100
d65c146b21
feat: add dynamically generated sysconfig replacement mappings (#13441)
## Summary

Implementation referenced in
https://github.com/astral-sh/uv/pull/12239#issuecomment-2744880003

Closes #12919 #12901

This makes the sysconfig replacements mappings dynamically generated
from
https://github.com/astral-sh/python-build-standalone/blob/main/cpython-unix/targets.yml

## Test Plan

cargo dev tests, and tested scenario from
https://github.com/astral-sh/uv/issues/12901#issuecomment-2822107454
2025-06-02 10:58:30 -05:00
konsti
73eb2dfb1f
Remove winsafe (#13779)
We've been using a number of different winapi crates. This PR removes
winsafe in favor of the official windows-* crates, so all of uv's own
winapi calls go through the official windows-* crates.

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
2025-06-02 17:53:03 +02:00
Tobias Gårdhus
459c902425
add --show-extras to uv tool list to list extra requirements installed with tools (#13783)
## Summary

Implemented as suggested in #13761 

eg.

```
$ uv tool install 'harlequin[postgres]'
$ uv tool list --show-extras
harlequin v2.1.2 [extras: postgres]
- harlequin
```

## Test Plan

Added a new test with the argument along with the others from the `uv
tool list` cli.
2025-06-02 14:59:40 +00:00
corentin-ant
5400434957
Unify zip and async_zip compression methods (#13781)
## Summary

#13285 added additional compression methods for `async_zip`, but they
should also be added to `zip` to support local wheel installation, on
top of the ones retrieved over network.

## Test Plan

Installation of local wheels with alternative compression schemes now
works (e.g. `uv add test.whl`)
2025-06-02 14:39:31 +02:00
Michał Górny
b5e7ad2c6d
Update lock::lock_requires_python not to require Python 3.8 (#13780)
Some checks are pending
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 | 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
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 ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (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
## Summary

Update `lock::lock_requires_python` not to require Python 3.8.

Fixes #13676

## Test Plan

`cargo test --no-default-features --features git,pypi,python` after
removing Python 3.8.
2025-06-02 09:10:51 +00:00
Eric Egli
290849d438
Update dockerfile path in contributing docs (#13751)
<!--
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

Sets the correct path to the builder dockerfile in the contributing
docs.

---------

Co-authored-by: konsti <konstin@mailbox.org>
2025-06-02 08:16:20 +00:00
renovate[bot]
25294a5393
Update Rust crate nix to 0.30.0 (#13773)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [nix](https://redirect.github.com/nix-rust/nix) |
workspace.dependencies | minor | `0.29.0` -> `0.30.0` |

---

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

---

### Release Notes

<details>
<summary>nix-rust/nix (nix)</summary>

###
[`v0.30.1`](https://redirect.github.com/nix-rust/nix/blob/HEAD/CHANGELOG.md#0301---2025-05-04)

[Compare
Source](https://redirect.github.com/nix-rust/nix/compare/v0.30.0...v0.30.1)

##### Fixed

-   doc.rs build
    ([#&#8203;2634](https://redirect.github.com/nix-rust/nix/pull/2634))

###
[`v0.30.0`](https://redirect.github.com/nix-rust/nix/blob/HEAD/CHANGELOG.md#0300---2025-04-29)

[Compare
Source](https://redirect.github.com/nix-rust/nix/compare/v0.29.0...v0.30.0)

##### Added

-   Add socket option `IPV6_PKTINFO` for BSDs/Linux/Android, also
    `IPV6_RECVPKTINFO` for DragonFlyBSD
    ([#&#8203;2113](https://redirect.github.com/nix-rust/nix/pull/2113))
-   Add `fcntl`'s `F_PREALLOCATE` constant for Apple targets.
    ([#&#8203;2393](https://redirect.github.com/nix-rust/nix/pull/2393))
- Improve support for extracting the TTL / Hop Limit from incoming
packets
    and support for DSCP (ToS / Traffic Class).
    ([#&#8203;2425](https://redirect.github.com/nix-rust/nix/pull/2425))
- Add socket option IP_TOS (nix::sys::socket::sockopt::IpTos)
IPV6\_TCLASS
    (nix::sys::socket::sockopt::Ipv6TClass) on Android/FreeBSD
    ([#&#8203;2464](https://redirect.github.com/nix-rust/nix/pull/2464))
-   Add `SeekData` and `SeekHole` to `Whence` for hurd and apple targets
    ([#&#8203;2473](https://redirect.github.com/nix-rust/nix/pull/2473))
-   Add `From` trait implementation between `SocketAddr` and `Sockaddr`,
`Sockaddr6`
([#&#8203;2474](https://redirect.github.com/nix-rust/nix/pull/2474))
-   Added wrappers for `posix_spawn` API
    ([#&#8203;2475](https://redirect.github.com/nix-rust/nix/pull/2475))
-   Add the support for Emscripten.
    ([#&#8203;2477](https://redirect.github.com/nix-rust/nix/pull/2477))
-   Add fcntl constant `F_RDADVISE` for Apple target
    ([#&#8203;2480](https://redirect.github.com/nix-rust/nix/pull/2480))
-   Add fcntl constant `F_RDAHEAD` for Apple target
    ([#&#8203;2482](https://redirect.github.com/nix-rust/nix/pull/2482))
-   Add `F_LOG2PHYS` and `F_LOG2PHYS_EXT` for Apple target
    ([#&#8203;2483](https://redirect.github.com/nix-rust/nix/pull/2483))
- `MAP_SHARED_VALIDATE` was added for all linux targets. & `MAP_SYNC`
was added
    for linux with the exclusion of mips architecures, and uclibc
    ([#&#8203;2499](https://redirect.github.com/nix-rust/nix/pull/2499))
-   Add `getregs()`/`getregset()`/`setregset()` for Linux/musl/aarch64
    ([#&#8203;2502](https://redirect.github.com/nix-rust/nix/pull/2502))
-   Add FcntlArgs `F_TRANSFEREXTENTS` constant for Apple targets
    ([#&#8203;2504](https://redirect.github.com/nix-rust/nix/pull/2504))
-   Add `MapFlags::MAP_STACK` in `sys::man` for netbsd
    ([#&#8203;2526](https://redirect.github.com/nix-rust/nix/pull/2526))
-   Add support for `libc::LOCAL_PEERTOKEN` in `getsockopt`.
    ([#&#8203;2529](https://redirect.github.com/nix-rust/nix/pull/2529))
-   Add support for `syslog`, `openlog`, `closelog` on all `unix`.
    ([#&#8203;2537](https://redirect.github.com/nix-rust/nix/pull/2537))
-   Add the `TCP_FUNCTION_BLK` sockopt, on FreeBSD.
    ([#&#8203;2539](https://redirect.github.com/nix-rust/nix/pull/2539))
- Implements `Into<OwnedFd>` for
`PtyMaster/Fanotify/Inotify/SignalFd/TimerFd`
    ([#&#8203;2548](https://redirect.github.com/nix-rust/nix/pull/2548))
- Add `MremapFlags::MREMAP_DONTUNMAP` to `sys::mman::mremap` for linux
target.
    ([#&#8203;2555](https://redirect.github.com/nix-rust/nix/pull/2555))
- Added `sockopt_impl!` to the public API. It's now possible for users
to
    define
    their own sockopts without needing to make a PR to Nix.
    ([#&#8203;2556](https://redirect.github.com/nix-rust/nix/pull/2556))
-   Add the `TCP_FUNCTION_ALIAS` sockopt, on FreeBSD.
    ([#&#8203;2558](https://redirect.github.com/nix-rust/nix/pull/2558))
- Add `sys::mman::MmapAdvise` `MADV_PAGEOUT`, `MADV_COLD`,
`MADV_WIPEONFORK`,
    `MADV_KEEPONFORK` for Linux and Android targets
    ([#&#8203;2559](https://redirect.github.com/nix-rust/nix/pull/2559))
- Add socket protocol `Sctp`, as well as `MSG_NOTIFICATION` for
non-Android
Linux targets.
([#&#8203;2562](https://redirect.github.com/nix-rust/nix/pull/2562))
-   Added `from_owned_fd` constructor to `EventFd`
    ([#&#8203;2563](https://redirect.github.com/nix-rust/nix/pull/2563))
- Add `sys::mman::MmapAdvise` `MADV_POPULATE_READ`,
`MADV_POPULATE_WRITE` for
    Linux and Android targets
    ([#&#8203;2565](https://redirect.github.com/nix-rust/nix/pull/2565))
-   Added `from_owned_fd` constructor to
    `PtyMaster/Fanotify/Inotify/SignalFd/TimerFd`
    ([#&#8203;2566](https://redirect.github.com/nix-rust/nix/pull/2566))
-   Added `FcntlArg::F_READAHEAD` for FreeBSD target
    ([#&#8203;2569](https://redirect.github.com/nix-rust/nix/pull/2569))
-   Added `sockopt::LingerSec` for Apple targets
    ([#&#8203;2572](https://redirect.github.com/nix-rust/nix/pull/2572))
-   Added `sockopt::EsclBind` for solarish targets
    ([#&#8203;2573](https://redirect.github.com/nix-rust/nix/pull/2573))
-   Exposed the `std::os::fd::AsRawFd` trait method for
    `nix::sys::fanotify::Fanotify` struct
    ([#&#8203;2575](https://redirect.github.com/nix-rust/nix/pull/2575))
-   Add support for syslog's `setlogmask` on all `unix`.
    ([#&#8203;2579](https://redirect.github.com/nix-rust/nix/pull/2579))
-   Added Fuchsia support for `ioctl`.
    ([#&#8203;2580](https://redirect.github.com/nix-rust/nix/pull/2580))
-   Add `sys::socket::SockProtocol::EthIp`,
    `sys::socket::SockProtocol::EthIpv6`,
    `sys::socket::SockProtocol::EthLoop`
    ([#&#8203;2581](https://redirect.github.com/nix-rust/nix/pull/2581))
-   Add OpenHarmony target into CI and Update documents.
    ([#&#8203;2599](https://redirect.github.com/nix-rust/nix/pull/2599))
-   Added the TcpMaxSeg `setsockopt` option for apple targets
    ([#&#8203;2603](https://redirect.github.com/nix-rust/nix/pull/2603))
-   Add `FilAttach` and `FilDetach` to socket::sockopt for Illumos
    ([#&#8203;2611](https://redirect.github.com/nix-rust/nix/pull/2611))
-   Add `PeerPidfd` (`SO_PEERPIDFD`) to `socket::sockopt` for Linux
    ([#&#8203;2620](https://redirect.github.com/nix-rust/nix/pull/2620))
-   Added `socket::sockopt::AttachReusePortCbpf` for Linux
    ([#&#8203;2621](https://redirect.github.com/nix-rust/nix/pull/2621))
-   Add `ptrace::syscall_info` for linux/glibc
    ([#&#8203;2627](https://redirect.github.com/nix-rust/nix/pull/2627))

##### Changed

-   Module sys/signal now adopts I/O safety
    ([#&#8203;1936](https://redirect.github.com/nix-rust/nix/pull/1936))
- Change the type of the `name` argument of `memfd_create()` from
`&CStr` to
`<P: NixPath>(name: &P)`
([#&#8203;2431](https://redirect.github.com/nix-rust/nix/pull/2431))
-   Public interfaces in `fcntl.rs` and `dir.rs` now use I/O-safe types.
    ([#&#8203;2434](https://redirect.github.com/nix-rust/nix/pull/2434))
-   Module `sys/stat` now adopts I/O safety.
    ([#&#8203;2439](https://redirect.github.com/nix-rust/nix/pull/2439))
-   Module unistd now adopts I/O safety.
    ([#&#8203;2440](https://redirect.github.com/nix-rust/nix/pull/2440))
-   Module sys/fanotify now adopts I/O safety
    ([#&#8203;2443](https://redirect.github.com/nix-rust/nix/pull/2443))
- Socket option `IpTos` has been renamed to `Ipv4Tos`, the old symbol is
deprecated since 0.30.0
([#&#8203;2465](https://redirect.github.com/nix-rust/nix/pull/2465))
- Rename Flags `EventFlag` to `EvFlags`, and `MemFdCreateFlag` to
`MFdFlags`
    ([#&#8203;2476](https://redirect.github.com/nix-rust/nix/pull/2476))
-   Made `nix::sys::socket::UnknownCmsg` public and more readable
    ([#&#8203;2520](https://redirect.github.com/nix-rust/nix/pull/2520))
-   recvmsg: take slice for cmsg_buffer instead of Vec
    ([#&#8203;2524](https://redirect.github.com/nix-rust/nix/pull/2524))
-   linkat: allow distinct types for path arguments
    ([#&#8203;2582](https://redirect.github.com/nix-rust/nix/pull/2582))

##### Fixed

-   Disable unsupported signals on sparc-linux
    ([#&#8203;2454](https://redirect.github.com/nix-rust/nix/pull/2454))
-   Fix cmsg_len() return type on OpenHarmony
    ([#&#8203;2456](https://redirect.github.com/nix-rust/nix/pull/2456))
- The `ns` argument of `sys::prctl::set_timerslack()` should be of type
`c_ulong`
([#&#8203;2505](https://redirect.github.com/nix-rust/nix/pull/2505))
- Properly exclude NUL characters from `OSString`s returned by
`getsockopt`.
    ([#&#8203;2557](https://redirect.github.com/nix-rust/nix/pull/2557))
-   Fixes the build on OpenHarmony
    ([#&#8203;2587](https://redirect.github.com/nix-rust/nix/pull/2587))

##### Removed

- Type `SigevNotify` is no longer `PartialEq`, `Eq` and `Hash` due to
the use
of `BorrowedFd`
([#&#8203;1936](https://redirect.github.com/nix-rust/nix/pull/1936))
- `EventFd::defuse()` is removed because it does nothing,
`EventFd::arm()` is
    also removed for symmetry reasons.
    ([#&#8203;2452](https://redirect.github.com/nix-rust/nix/pull/2452))
-   Removed the `Copy` trait from `PollFd`
    ([#&#8203;2631](https://redirect.github.com/nix-rust/nix/pull/2631))

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4zMy42IiwidXBkYXRlZEluVmVyIjoiNDAuMzMuNiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-06-02 08:05:01 +00:00
Ben Beasley
73829f3bf4
Conditionalize more tests that require PyPI (#13699)
<!--
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? -->
Use the existing `pypi` feature to conditionalize a number of tests that
attempt to access https://pypi.org and/or
https://files.pythonhosted.org. See
https://github.com/astral-sh/uv/issues/8970#issuecomment-2466794088.

There is no reason to believe that these are *all* of the tests that
need to be conditionalized on the `pypi` feature, but this should be a
solid step in the right direction.

## Test Plan

<!-- How was it tested? -->

This allows me to build and run the integration tests in [Fedora’s `uv`
package](https://src.fedoraproject.org/rpms/uv) without having to
manually skip tests that try to access PyPI. I confirmed that this
appears to accomplish that goal.

Otherwise, this should be tested by building and running the tests as
usual. As mentioned in
https://github.com/astral-sh/uv/issues/8970#issuecomment-2516181501, a
more complete solution would include CI tests that confirm these
features are working as intended. I’m not in a position to offer that.
2025-06-02 09:57:03 +02:00
renovate[bot]
1e890b5ac7
Update taiki-e/install-action action to v2.52.4 (#13778)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[taiki-e/install-action](https://redirect.github.com/taiki-e/install-action)
| action | minor | `v2.50.3` -> `v2.52.4` |

---

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

---

### Release Notes

<details>
<summary>taiki-e/install-action (taiki-e/install-action)</summary>

###
[`v2.52.4`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.52.4):
2.52.4

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.52.3...v2.52.4)

-   Update `cargo-binstall@latest` to 1.12.6.

-   Update `wash@latest` to 0.42.0.

###
[`v2.52.3`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.52.3):
2.52.3

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.52.2...v2.52.3)

-   Update `cargo-nextest@latest` to 0.9.97.

-   Update `trivy@latest` to 0.63.0.

-   Update `protoc@latest` to 3.31.1.

###
[`v2.52.2`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.52.2):
2.52.2

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.52.1...v2.52.2)

-   Update `mdbook@latest` to 0.4.51.

###
[`v2.52.1`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.52.1):
2.52.1

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.52.0...v2.52.1)

-   Update `taplo@latest` to 0.10.0.

-   Update `mdbook@latest` to 0.4.50.

-   Update `deepsource@latest` to 0.9.0.

-   Update `cargo-shear@latest` to 1.3.0.

###
[`v2.52.0`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.52.0):
2.52.0

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.51.3...v2.52.0)

- Support `trivy`.
([#&#8203;970](https://redirect.github.com/taiki-e/install-action/pull/970),
thanks [@&#8203;jayvdb](https://redirect.github.com/jayvdb))

-   Update `syft@latest` to 1.26.1.

-   Update `rclone@latest` to 1.69.3.

-   Update `cargo-shear@latest` to 1.2.8.

###
[`v2.51.3`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.51.3):
2.51.3

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.51.2...v2.51.3)

-   Update `wasmtime@latest` to 33.0.0.

-   Update `cargo-tarpaulin@latest` to 0.32.7.

-   Update `espup@latest` to 0.15.1.

-   Update `dprint@latest` to 0.50.0.

###
[`v2.51.2`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.51.2):
2.51.2

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.51.1...v2.51.2)

-   Update `syft@latest` to 1.25.1.

-   Update `release-plz@latest` to 0.3.135.

###
[`v2.51.1`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.51.1):
2.51.1

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.51.0...v2.51.1)

-   Update `syft@latest` to 1.25.0.

-   Update `cargo-binstall@latest` to 1.12.5.

###
[`v2.51.0`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.51.0):
2.51.0

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.10...v2.51.0)

- Support `cargo-shear`.
([#&#8203;962](https://redirect.github.com/taiki-e/install-action/pull/962),
thanks [@&#8203;vivienm](https://redirect.github.com/vivienm))

-   Update `grcov@latest` to 0.10.0.

-   Update `cargo-nextest@latest` to 0.9.96.

-   Update `protoc@latest` to 3.31.0.

-   Update `syft@latest` to 1.24.0.

###
[`v2.50.10`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.10):
2.50.10

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.9...v2.50.10)

-   Update `trunk@latest` to 0.21.14.

-   Update `release-plz@latest` to 0.3.134.

-   Update `cargo-binstall@latest` to 1.12.4.

###
[`v2.50.9`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.9):
2.50.9

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.8...v2.50.9)

-   Update `editorconfig-checker@latest` to 3.3.0.

-   Update `cargo-lambda@latest` to 1.8.5.

###
[`v2.50.8`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.8):
2.50.8

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.7...v2.50.8)

-   Update `cargo-tarpaulin@latest` to 0.32.5.

-   Update `mdbook@latest` to 0.4.49.

###
[`v2.50.7`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.7):
2.50.7

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.6...v2.50.7)

-   Update `cargo-tarpaulin@latest` to 0.32.4.

###
[`v2.50.6`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.6):
2.50.6

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.5...v2.50.6)

-   Update `knope@latest` to 0.20.0.

###
[`v2.50.5`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.5):
2.50.5

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.4...v2.50.5)

-   Update `xh@latest` to 0.24.1.

-   Update `typos@latest` to 1.32.0.

-   Update `rclone@latest` to 1.69.2.

###
[`v2.50.4`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.50.4):
2.50.4

[Compare
Source](https://redirect.github.com/taiki-e/install-action/compare/v2.50.3...v2.50.4)

-   Update `typos@latest` to 1.31.2.

-   Update `osv-scanner@latest` to 2.0.2.

-   Update `cargo-nextest@latest` to 0.9.95.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4zMy42IiwidXBkYXRlZEluVmVyIjoiNDAuMzMuNiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 09:50:01 +02:00
renovate[bot]
b112baccff
Update Rust crate tempfile to v3.20.0 (#13776)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [tempfile](https://stebalien.com/projects/tempfile-rs/)
([source](https://redirect.github.com/Stebalien/tempfile)) |
workspace.dependencies | minor | `3.19.1` -> `3.20.0` |

---

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

---

### Release Notes

<details>
<summary>Stebalien/tempfile (tempfile)</summary>

###
[`v3.20.0`](https://redirect.github.com/Stebalien/tempfile/blob/HEAD/CHANGELOG.md#3200)

[Compare
Source](https://redirect.github.com/Stebalien/tempfile/compare/v3.19.1...v3.20.0)

This release mostly unifies the behavior/capabilities around "keeping"
temporary files:

- Rename `Builder::keep(bool)` (via deprecation) to
`Builder::disable_cleanup(bool)` to make it clear that behaves
differently from `NamedTempFile::keep()`. The former disables automatic
cleanup while the latter *consumes* the `NamedTempFile` object entirely
and unsets the "temporary file" attribute (on Windows).
- Rename `TempDir::into_path` (via deprecation) to `TempDir::keep` to
mirror `NamedTempFile::keep`.
- Add `TempDir::disable_cleanup`, `NamedTempFile::disable_cleanup`, and
`TempPath::disable_cleanup` making it possible to disable automatic
cleanup in-place *after* creating a temporary file/directory (equivalent
to calling `Builder::disable_cleanup` before creating the
file/directory).

Additionally, it adds a few spooled temporary file features:

- Add `SpooledTempFile::into_file` for turning a `SpooledTempFile` into
a regular unnamed temporary file, writing it to the backing storage
("rolling" it) if it was still stored in-memory.
- Add `spooled_tempfile_in` and `SpooledTempFile::new_in` methods for
creating spooled temporary files in a specific directory. This makes it
possible to choose the backing device for your spooled temporary file
which is rather important on Linux where the default temporary directory
is likely backed by memory (defeating the entire point of having a
spooled temporary file).

Finally, this release improves documentation, especially the top-level
documentation explaining which temporary file type to use.

**BREAKING** for those with `deny(warnings)`:

-   `Builder::keep` deprecated in favor of `Builder::disable_cleanup`.
-   `TempDir::into_path` is deprecated in favor of `TempDir::keep`.

**BREAKING**:

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4zMy42IiwidXBkYXRlZEluVmVyIjoiNDAuMzMuNiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-06-02 07:47:08 +00:00
renovate[bot]
b144cfed87
Update Rust crate tokio to v1.45.1 (#13777)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [tokio](https://tokio.rs)
([source](https://redirect.github.com/tokio-rs/tokio)) |
dev-dependencies | minor | `1.44.2` -> `1.45.1` |
| [tokio](https://tokio.rs)
([source](https://redirect.github.com/tokio-rs/tokio)) |
workspace.dependencies | minor | `1.44.2` -> `1.45.1` |

---

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

---

### Release Notes

<details>
<summary>tokio-rs/tokio (tokio)</summary>

###
[`v1.45.1`](https://redirect.github.com/tokio-rs/tokio/releases/tag/tokio-1.45.1):
Tokio v1.45.1

[Compare
Source](https://redirect.github.com/tokio-rs/tokio/compare/tokio-1.45.0...tokio-1.45.1)

### 1.45.1 (May 24th, 2025)

This fixes a regression on the wasm32-unknown-unknown target, where code
that previously did not panic due to calls to `Instant::now()` started
failing. This is due to the stabilization of the first time-based
metric.

##### Fixed

- Disable time-based metrics on wasm32-unknown-unknown ([#&#8203;7322])

[#&#8203;7322]: https://redirect.github.com/tokio-rs/tokio/pull/7322

###
[`v1.45.0`](https://redirect.github.com/tokio-rs/tokio/releases/tag/tokio-1.45.0):
Tokio v1.45.0

[Compare
Source](https://redirect.github.com/tokio-rs/tokio/compare/tokio-1.44.2...tokio-1.45.0)

##### Added

- metrics: stabilize `worker_total_busy_duration`, `worker_park_count`,
and `worker_unpark_count` ([#&#8203;6899], [#&#8203;7276])
-   process: add `Command::spawn_with` ([#&#8203;7249])

##### Changed

-   io: do not require `Unpin` for some trait impls ([#&#8203;7204])
-   rt: mark `runtime::Handle` as unwind safe ([#&#8203;7230])
-   time: revert internal sharding implementation ([#&#8203;7226])

##### Unstable

-   rt: remove alt multi-threaded runtime ([#&#8203;7275])

[#&#8203;6899]: https://redirect.github.com/tokio-rs/tokio/pull/6899

[#&#8203;7276]: https://redirect.github.com/tokio-rs/tokio/pull/7276

[#&#8203;7249]: https://redirect.github.com/tokio-rs/tokio/pull/7249

[#&#8203;7204]: https://redirect.github.com/tokio-rs/tokio/pull/7204

[#&#8203;7230]: https://redirect.github.com/tokio-rs/tokio/pull/7230

[#&#8203;7226]: https://redirect.github.com/tokio-rs/tokio/pull/7226

[#&#8203;7275]: https://redirect.github.com/tokio-rs/tokio/pull/7275

</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 these
updates 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:eyJjcmVhdGVkSW5WZXIiOiI0MC4zMy42IiwidXBkYXRlZEluVmVyIjoiNDAuMzMuNiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 09:44:07 +02:00
renovate[bot]
518a4e6a9c
Update Rust crate reqwest to v0.12.18 (#13768)
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.18` |

---

> [!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.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:eyJjcmVhdGVkSW5WZXIiOiI0MC4zMy42IiwidXBkYXRlZEluVmVyIjoiNDAuMzMuNiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 09:32:26 +02:00
Michał Górny
59efe06aaf
Update more tests not to use Python 3.8 (#13755)
## Summary

Update a few more tests to avoid using Python 3.8 unnecessarily. From
what I can see, neither of these really need that specific Python
version, so just update them to use 3.9 instead.

Bug #13676

## Test Plan

Uninstall Python 3.8 and run: `cargo test --no-default-features
--features git,pypi,python`

One test failure remains.
2025-06-02 09:22:35 +02:00
renovate[bot]
9423f05ca7
Update Rust crate hyper-util to v0.1.13 (#13767)
Some checks are pending
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 cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (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 | x86-64 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
2025-06-01 22:02:11 -04:00
renovate[bot]
490a3a1909
Update pre-commit hook astral-sh/ruff-pre-commit to v0.11.12 (#13764) 2025-06-01 21:59:34 -04:00
renovate[bot]
53efc0cf6d
Update docker/build-push-action action to v6.18.0 (#13770) 2025-06-01 21:57:51 -04:00
renovate[bot]
6fbdb8de84
Update Rust crate goblin to 0.10.0 (#13772) 2025-06-01 21:57:28 -04:00
renovate[bot]
e0821176a4
Update Rust crate criterion to 0.6.0 (#13771) 2025-06-01 21:57:25 -04:00
renovate[bot]
a0d60eef12
Update Rust crate winsafe to 0.0.24 (#13769) 2025-06-01 21:57:15 -04:00
renovate[bot]
3b7bfed6f9
Update Rust crate clap to v4.5.39 (#13766) 2025-06-01 21:57:04 -04:00
renovate[bot]
14598f811f
Update Rust crate backon to v1.5.1 (#13765) 2025-06-02 00:53:08 +00:00
Zanie Blue
691a4f1379
Propagate credentials to files on devpi indexes ending in /+simple (#13743)
Closes https://github.com/astral-sh/uv/issues/13737

Not much to say here — devpi is common enough that we should support
their weird `/+simple` URL format.
2025-06-01 20:20:56 -04:00
Zanie Blue
13a86a23b3
Bump version to 0.7.9 (#13739)
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 ubuntu (push) Has been cancelled
CI / check system | python on opensuse (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 | pyston (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 | 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
2025-05-30 14:30:37 -05:00
konsti
483b4c82e8
Don't fail direct URL hash checking with dependency metadata (#13736)
Some checks are pending
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 | 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 | 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 opensuse (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 | 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
Fixes #12512
2025-05-30 19:39:40 +02:00
Aria Desires
891fe524d9
update python build standalone, unblocklist linux updates (#13732) 2025-05-30 12:33:21 -04:00
Jack O'Connor
7310ea75da
allow running non-default Python interpreters directly via uvx (#13583)
Previously if you wanted to run e.g. PyPy via `uvx`, you had to spell it
like `uvx -p pypy python`. Now we reuse some of the
`PythonRequest::parse` machinery to handle the executable, so all of the
following examples work:

- `uvx python3.8`
- `uvx 'python>3.7,<3.9'`
- `uvx --from python3.8 python` (or e.g. `bash`)
- `uvx pypy38`
- `uvx graalpy@38`

The `python` (and on Windows only, `pythonw`) special cases are
retained, which normally aren't allowed values of `-p`/`--python`.

Closes https://github.com/astral-sh/uv/issues/13536.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
Co-authored-by: konsti <konstin@mailbox.org>
2025-05-30 09:12:39 -07:00
Zanie Blue
4cc5291c08
Allow discovery of x86-64 managed Python builds on macOS (#13722)
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 opensuse (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 | 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 | 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
Replacement for https://github.com/astral-sh/uv/pull/13474 (clobbered by
a changed base)

Once these are explicitly installed, they should be discoverable and
usable. Currently, they are not.
2025-05-29 17:55:21 -05:00
Zanie Blue
0c5ae1f25c
Differentiate between implicit vs explicit architecture requests (#13723)
In https://github.com/astral-sh/uv/pull/13721#issuecomment-2920530601 I
presumed that all the installation problems in
https://github.com/astral-sh/uv/pull/13722 were solved by
https://github.com/astral-sh/uv/pull/13709 but they were not because we
don't differentiate between implicit and explicit architecture requests
so a request for `aarch64` is considered satisfied by an existing
`x86-64` installation even if the user explicitly requested that
architecture.

Now, we track if it was explicit or implicit, requiring an exact match
in the former case, and a `supports` in the latter.

We considered doing this for other items in the request, like the
operating system but we don't have a `supports()` concept there. It
might make sense for libc in the future.
2025-05-29 22:04:57 +00:00
Aria Desires
067b03cc9a
Only show the first match per platform (and architecture) by default in uv python list (#13721)
This is an alternative to #13701
2025-05-29 17:38:44 -04:00
Zanie Blue
dfc85336f8
Implement ordering for Python architectures to prefer native installations (#13709)
Resolves
https://github.com/astral-sh/uv/pull/13474#discussion_r2112586405

This kind of dynamic ordering freaks me out a little, but I think it's
probably the best solution and is static at compile-time.

Currently, we're just sorting by the stringified representation! which
is just convenient for reproducibility, but we rely on these orderings
for prioritization in discovery.
2025-05-29 19:06:33 +00:00
Zanie Blue
59070b5b3f
Use codspeed runner for wall time benchmarking (#13586)
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 ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (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 | 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
We couldn't use the CodSpeed "walltime" runner because it required
administrative permissions on our repositories, but following some
feedback they've adjusted the required permissions so we can give it a
try now.

As a brief background, CodSpeed uses Valgrind for instrumented
benchmarking, emulating the execution for improved stability on GitHub's
runners. This is nice, but means things like allocs and io are not
measured. Now, they support standard wall time benchmarking, using their
own managed runners for stable measurements. Here, we add support for
those while retaining the old workflow — you can toggle between views in
their UI.
2025-05-29 12:52:17 -05:00
Jack O'Connor
08f2fa48ff
make the error message clearer when running distroless containers (#13549)
Previously you could get a confusing error message like this:

```
$ docker run ghcr.io/astral-sh/uv run python
error: Could not read ELF interpreter from any of the following paths: /bin/sh, /usr/bin/env, /bin/dash, /bin/ls
```

Now the error message is better:

```
error: Failed to discover managed Python installations
  Caused by: Failed to determine the libc used on the current platform
  Caused by: Failed to find any common binaries to determine libc from: /bin/sh, /usr/bin/env, /bin/dash, /bin/ls
```

See https://github.com/astral-sh/uv/issues/8635.

---------

Co-authored-by: konsti <konstin@mailbox.org>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-29 10:29:01 -07:00
johnthagen
72e2821d26
Fix exclude-newer date format in docs (#13706)
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 opensuse (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 | 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 (push) Blocked by required conditions
## Summary

Closes #13704
2025-05-28 20:23:10 +00:00
Reci
e5d002beb1
Add uvw as alias for uv without console window on Windows (#11786)
<!--
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

Related to https://github.com/astral-sh/uv/issues/6801.

Currently on Windows, uv itself will always creates a console window,
even though the window could be empty if `uv run --gui-script` is used.
This is due to it using the [default `console` window
subsystem](https://rust-lang.github.io/rfcs/1665-windows-subsystem.html).

This PR introduces a wrapper `uvw` that, similar to the existing `uvx`,
invokes `uv` with the
[`CREATE_NO_WINDOW`](https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags#:~:text=CREATE_NO_WINDOW)
process creation flag on Windows, which creates child process without
console window.

Note that this PR does not alter any behaviors regarding `run --script`
and `run --gui-script`.

## Test Plan

Built and tested locally by doing something like `uvw run test.py`.
2025-05-28 14:37:21 -04:00
konsti
f62836fa04
Windows paths are valid URLs (#13625)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (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 | 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 (push) Blocked by required conditions
Currently, it is not possible to set a custom Python downloads JSON on
Windows, as Windows paths can be valid URLs.

```rust
use url::Url;

fn main() {
    dbg!(Url::parse(r"C:\Users\Ferris\download.json"));
}
```

Tested by https://github.com/astral-sh/uv/pull/13585 (where it is
currently failing CI).
2025-05-28 10:11:56 -05:00
konsti
fc77be09f4
Use only a single 3.13t Linux integration test (#13700)
Fixes https://github.com/astral-sh/uv/issues/13681

We're still using the apt repo in the deadsnakes test but this is one
less location with the flaky apt script.
2025-05-28 16:15:02 +02:00
Zanie Blue
56ce40b0f4
Update packse scenarios (#13688)
Closes #13676 

See https://github.com/astral-sh/packse/pull/242 and
https://github.com/astral-sh/packse/releases/tag/0.3.47
2025-05-28 08:58:38 -05:00
konsti
56203484a2
Add uv add --bounds to configure the version constraint (#12946)
By default, uv uses only a lower bound in `uv add`, which avoids
dependency conflicts due to upper bounds. With this PR, this cna be
changed by setting a different bound kind. The bound kind can be
configured in `uv.toml`, as a user preference, in `pyproject.toml`, as a
project preference, or on the CLI, when adding a specific project.

We add two options that add an upper bound on the constraint, one for
SemVer (`>=1.2.3,<2.0.0`, dubbed "major", modeled after the SemVer
caret) and another one for dependencies that make breaking changes in
minor version (`>=1.2.3,<1.3.0`, dubbed "minor", modeled after the
SemVer tilde). Intuitively, the major option bumps the most significant
version component, while the minor option bumps the second most
significant version component. There is also an exact bounds option
(`==1.2.3`), though generally we recommend setting a wider bound and
using the lockfile for pinning.

Versions can have leading zeroes, such as `0.1` or `0.0.1`. For a single
leading 0, we shift the the meaning of major and minor similar to cargo.
For two or more leading zeroes, the difference between major and minor
becomes inapplicable, instead both bump the most significant component:
- major: `0.1` -> `>=0.1,<0.2`
- major: `0.0.1` -> `>=0.0.1,<0.0.2`
- major: `0.0.1.1` -> `>=0.0.1.1,<0.0.2.0`
- major: `0.0.0.1` -> `>=0.0.0.1,<0.0.0.2`
- minor: `0.1` -> `>=0.1,<0.1.1`
- minor: `0.0.1` -> `>=0.0.1,<0.0.2`
- minor: `0.0.1.1` -> `>=0.0.1.1,<0.0.2.0`
- minor: `0.0.0.1` -> `>=0.0.0.1,<0.0.0.2`

For a consistent appearance, we try to preserve the number of components
in the upper bound. For example, adding a version `2.17` with the major
option is stored as `>=2.17,<3.0`. If a version uses three components
and is greater than 0, both bounds will also use three components
(SemVer versions always have three components). Of the top 100 PyPI
packages, 8 use a non-three-component version (docutils, idna, pycparser
and soupsieve with two components, packaging, pytz and tzdata with two
component, CalVer and trove-classifiers with four component CalVer).
Example `pyproject.toml` files with the top 100 packages: [`--bounds
major`](https://gist.github.com/konstin/0aaffa9ea53c4834c22759e8865409f4)
and [`--bounds
minor`](https://gist.github.com/konstin/e77f5e990a7efe8a3c8a97c5c5b76964).
While many projects follow version scheme that roughly or directly
matches the major or minor options, these compatibility ranges are
usually not applicable for the also popular CalVer versioning.

For pre-release versions, there are two framings we could take: One is
that pre-releases generally make no guarantees about compatibility
between them and are used to introduce breaking changes, so we should
pin them exactly. In many cases however, pre-release specifiers are used
because a project needs a bugfix or a feature that hasn't made it into a
stable release, or because a project is compatible with the next version
before a final version for that release is published. In those cases,
compatibility with other packages that depend on the same library is
more important, so the desired bound is the same as it would be for the
stable release, except with the lower bound lowered to include
pre-release.

The names of the bounds and the name of the flag is up for bikeshedding.
Currently, the option is call `tool.uv.bounds`, but we could also move
it under `tool.uv.edit.bounds`, where it would be the first/only entry.

Fixes #6783

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-28 13:11:31 +00:00
Charles Tapley Hoyt
3ee8028bb4
Improve performance of uv-python crate's manylinux submodule (#11131)
## Summary

This PR makes a few performance improvements:

1. Reduces the need to unpack and repack a `_GLibCVersion` tuple
2. Reduces the doubled call to `_is_compatible(arch, glibc_version)`
3. Moves the assignment of the `tag` variable directly into the yield,
reducing memory allocation in case this is never used when
`_is_compatible(arch, glibc_version)` is false
4. Combines the check of the `glibc_version` being in
`_LEGACY_MANYLINUX_MAP` and the assignment to the variable together. I'm
not sure if this is actually better, but using the assignment expression
reduces this from 4 lines to 2

## Test Plan

I upstreamed these changes in
https://github.com/pypa/packaging/pull/869. Otherwise, I'm pretty
confident this is a minor change that works the same
2025-05-28 15:09:20 +02:00
konsti
de64f1dfa8
Use ref-cast for DisplaySafeUrl (#13696)
By default, Rust does not support safe cast from `&U` to `&T` for
`#[repr(transparent)] T(U)` even if the newtype opts in. The dtolnay
ref-cast crate fills this gap, allowing to remove `DisplaySafeUrlRef`.
2025-05-28 11:28:28 +00:00
John Mumm
410dc33574
Make DisplaySafeUrlRef Copy and other minor PR follow-ups (#13683)
This PR implements a few review follow-ups from #13560. In particular,
it
* Makes `DisplaySafeUrlRef` implement `Copy` so that it can be passed by
value.
* Updates `to_string_with_credentials` methods with
`displayable_with_credentials`, returning an `impl Display` instead of
`String` for greater flexibility.
* Updates the `DisplaySafeUrl` and `DisplaySafeUrlRef` `Debug`
implementations to match the underlying `Url` `Debug` implementation
(with the exception that credentials are masked).
* Replaces an unnecessary `DisplaySafeUrl::from(Url::from_file_path`
with `DisplaySafeUrl::from_file_path`
2025-05-28 06:36:18 -04:00
Zanie Blue
90a21ae46a
Add example of enabling Dependabot (#13692)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | windows registry (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 opensuse (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 | 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 (push) Blocked by required conditions
Follows https://github.com/astral-sh/uv/pull/13690

Tested in
https://github.com/astral-sh/packse/blob/main/.github/dependabot.yml
2025-05-28 11:10:14 +02:00
Akshay Agrawal
20cfc93c58
docs: integration with marimo guide (#13691)
Some checks are pending
CI / check cache | ubuntu (push) Blocked by required conditions
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 opensuse (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 | 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 (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

This change adds a new integration guide, on using uv with marimo
notebooks. It is similar to but simpler than the existing Jupyter guide,
since marimo stores notebooks as Python files and also integrates
tightly with uv for package management.

The guide showcases four ways of using uv with marimo:

1. marimo as a standalone tool (`uvx`)
2. managing inline script metadata (an alternative to Jupyter kernels,
marimo has no concept of kernels)
3. in project environments
4. in non-project environments

## Test Plan

N/A as this is a docs-only change.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-27 18:43:43 -05:00
konsti
95c1463965
Update dependabot support status (#13690)
Following user reports and
https://github.com/dependabot/dependabot-core/issues?q=state%3Aopen%20label%3A%22L%3A%20python%3Auv%22%20sort%3Areactions-%2B1-desc,
we're updating the dependabot support as partial.

See https://github.com/astral-sh/uv/issues/2512#issuecomment-2900063741
2025-05-27 16:55:12 -05:00
Zanie Blue
32b949c3a8
Avoid using 3.8 in tests when feasible (#13680)
See https://github.com/astral-sh/uv/issues/13676

Python 3.8 is EOL, and we should avoid using it for tests unless we're
covering 3.8-specific behaviors.

In some cases, the Python version we require for the test is arbitrary,
for which I've added a new constant (set to 3.12). In other cases, we
require an older Python version for compatibility with various packages,
like `setuptools`. For those, we can _probably_ switch to a newer
version but it'd be more invasive as we'd need to change our constraints
or `exclude-newer`.

Adds a feature flag for cases where we still need to use the EOL
version.

There's a lot of usage in packse scenarios too, I'll update those
separately because the diff will be large.
2025-05-27 18:34:49 +00:00
Eva Müller
df00189ec5
docs: Explicitly specify to add a new repo entry to the repos list item in the .pre-commit-config.yaml (#10243)
<!--
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

When creating the `.pre-commit-config.yaml` from scratch, although
following https://pre-commit.com/, it might be easy to overlook that the
pre-commit repo examples need to be added below the `repos` list item to
get a valid `yaml` file.

Additionally, updated the version of the first two examples.

## Test Plan

I followed the `CONTRIBUTING.md` and the result looked fine.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-27 16:25:23 +00:00
Jay Qi
2db1630f54
Add documentation about Python versions to Tools concept page (#7673)
<!--
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

Add documentation about Python versions to Tools concept page

## Test Plan

N/A

---------

Co-authored-by: Jay Qi <jayqi@users.noreply.github.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-27 16:23:29 +00:00
Peter Gaultney
4f34eafbd2
add pronunciation to README (#5336)
## Summary

Adds an IPA pronunciation to the very top of the README, for the sake of
clarity. This is a minor thing, but it's nice to know that there's a
'standard' pronunciation for uv.

I have no idea whether this will seem like a "reasonable" place to put
this; I looked over the README and didn't see any obviously more
appropriate places to put it. Maybe this is unobtrusive enough that it's
fine where it is; maybe there should be a new section added somewhere;
maybe somebody who has a better feel for the project goals will have a
clever suggestion.

Closes #5309

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-05-27 16:11:54 +00:00
konsti
abd5fd199c
Increase deadsnake timeout to 15min (#13661)
4290036659
2025-05-27 09:37:14 -05:00
Michael Gathara
7e39a80b18
Include pre-release versions in uv python install --reinstall (#13645)
<!--
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? -->
This change allows for `uv python install --reinstall` to include
pre-releases when reinstalling. It does this by explicitly allowing
pre-releases to be included within `PythonRequest::Any` if the user does
not specify a version to reinstall.

Fixes #13582

## Test Plan

<!-- How was it tested? -->
```bash
uv python install 3.14 3.13 3.10
uv python install --no-config --reinstall
```
2025-05-27 09:35:48 -05:00
konsti
a7ae768118
Build s390x on nightly (#13665)
Build s390x on nightly due to llvm performance regressions see
https://github.com/rust-lang/rust/issues/141287. To be undone when the
llvm fixes land on stable.

This should fix the timeouts in
4291543960
2025-05-27 09:32:08 -05:00
Alex Waygood
7bba3d00d4
Write the path of the parent environment to an extends-environment key in the pyvenv.cfg file of an ephemeral environment (#13598) 2025-05-27 13:46:28 +01:00
Arne Küderle
f657359729
Quote versions variables in GitLab documentation
## Summary

Fixes #13675

## Test Plan

New example was tested manually to verify that it works.
2025-05-27 08:43:30 -04:00
Charlie Marsh
9a1d977e7e
Avoid reinstalling dependency group members with --all-packages (#13678)
## Summary

Right now, if a workspace member is first created by way of being a dev
dependency on another member, we end up duplicating it in the graph.
Instead, we should create all the roots upfront; all subsequent node
creations are robust to existing nodes.

Closes
https://github.com/astral-sh/uv/issues/13673#issuecomment-2912196406.
2025-05-27 08:43:07 -04:00
Dennis Dang
33d8f69076
Exit early on self update if global --offline is set (#13663)
## Summary
Resolves https://github.com/astral-sh/uv/issues/13580.

`uv self update --offline` should fail and exit early because
self-updating requires network connection.

## Test Plan
A snapshot test is added.

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
Co-authored-by: konsti <konstin@mailbox.org>
2025-05-27 03:29:58 +00:00
Charlie Marsh
71c0e6de50
Reduce number of reference-checks for uv cache clean (#13669)
## Summary

This should reduce the number of filesystem operations fairly
dramatically:

- Only query actual symlinks.
- Don't recurse into package bodies (huge).
- Only traverse once (rather than twice).

Closes https://github.com/astral-sh/uv/issues/13667.
2025-05-26 21:43:24 -04:00
John Mumm
c19a294a48
Add DisplaySafeUrl newtype to prevent leaking of credentials by default (#13560)
Prior to this PR, there were numerous places where uv would leak
credentials in logs. We had a way to mask credentials by calling methods
or a recently-added `redact_url` function, but this was not secure by
default. There were a number of other types (like `GitUrl`) that would
leak credentials on display.

This PR adds a `DisplaySafeUrl` newtype to prevent leaking credentials
when logging by default. It takes a maximalist approach, replacing the
use of `Url` almost everywhere. This includes when first parsing config
files, when storing URLs in types like `GitUrl`, and also when storing
URLs in types that in practice will never contain credentials (like
`DirectorySourceUrl`). The idea is to make it easy for developers to do
the right thing and for the compiler to support this (and to minimize
ever having to manually convert back and forth). Displaying credentials
now requires an active step. Note that despite this maximalist approach,
the use of the newtype should be zero cost.

One conspicuous place this PR does not use `DisplaySafeUrl` is in the
`uv-auth` crate. That would require new clones since there are calls to
`request.url()` that return a `&Url`. One option would have been to make
`DisplaySafeUrl` wrap a `Cow`, but this would lead to lifetime
annotations all over the codebase. I've created a separate PR based on
this one (#13576) that updates `uv-auth` to use `DisplaySafeUrl` with
one new clone. We can discuss the tradeoffs there.

Most of this PR just replaces `Url` with `DisplaySafeUrl`. The core is
`uv_redacted/lib.rs`, where the newtype is implemented. To make it
easier to review the rest, here are some points of note:

* `DisplaySafeUrl` has a `Display` implementation that masks
credentials. Currently, it will still display the username when there is
both a username and password. If we think is the wrong choice, it can
now be changed in one place.
* `DisplaySafeUrl` has a `remove_credentials()` method and also a
`.to_string_with_credentials()` method. This allows us to use it in a
variety of scenarios.
* `IndexUrl::redacted()` was renamed to
`IndexUrl::removed_credentials()` to make it clearer that we are not
masking.
* We convert from a `DisplaySafeUrl` to a `Url` when calling `reqwest`
methods like `.get()` and `.head()`.
* We convert from a `DisplaySafeUrl` to a `Url` when creating a
`uv_auth::Index`. That is because, as mentioned above, I will be
updating the `uv_auth` crate to use this newtype in a separate PR.
* A number of tests (e.g., in `pip_install.rs`) that formerly used
filters to mask tokens in the test output no longer need those filters
since tokens in URLs are now masked automatically.
* The one place we are still knowingly writing credentials to
`pyproject.toml` is when a URL with credentials is passed to `uv add`
with `--raw`. Since displaying credentials is no longer automatic, I
have added a `to_string_with_credentials()` method to the `Pep508Url`
trait. This is used when `--raw` is passed. Adding it to that trait is a
bit weird, but it's the simplest way to achieve the goal. I'm open to
suggestions on how to improve this, but note that because of the way
we're using generic bounds, it's not as simple as just creating a
separate trait for that method.
2025-05-27 00:05:30 +02:00
konsti
b80cafd5e8
Stack traces from Windows CI crashes (#13656)
We regularly have Windows CI crashing with `exit_code: -1073741819`, a
recent example is
<4286957096>.
This code apparently means Access Violation, akin to a Segmentation
Fault. Lacking local reproducibility (at least I never saw this on my
Windows machine), I generated workflow steps that will hopefully give us
a stack trace (and only fail an already failed job when they are
actually bogus; I didn't find any good references).
2025-05-26 22:22:42 +02:00
Aria Desires
cd8171d2a1
Unwire PackageMetadata fields (#13635)
PackageMetadata, for whatever reason, does not have a mirrored Wire type
so it was easy to not realize that it contains markers that need to be
complexified.

Fixes #13614

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-05-26 14:17:19 -04:00
konsti
6ab1d12480
Avoid rendering info log level (#13642)
We were previously rendering messages for the info level, carrying
overhead in pubgrub which using `log::info!`. We avoid this by only
configuring `LevelFilter::INFO` if the durations layer exists.

I've confirmed that the default `Subscriber::max_level_hint` goes from
`INFO` to `OFF` and the profile skips `Incompatibility::display`.
2025-05-26 15:17:15 +02:00
konsti
a6f8fa7e42
Optimize Version display (#13643)
We format enough versions that the `.collect::<Vec<String>>()` showed up
in profiles.
2025-05-26 15:17:07 +02:00
renovate[bot]
7941d215e5
Update actions/attest-build-provenance action to v2.3.0 (#13650)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[actions/attest-build-provenance](https://redirect.github.com/actions/attest-build-provenance)
| action | minor | `v2.2.3` -> `v2.3.0` |

---

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

---

### Release Notes

<details>
<summary>actions/attest-build-provenance
(actions/attest-build-provenance)</summary>

###
[`v2.3.0`](https://redirect.github.com/actions/attest-build-provenance/releases/tag/v2.3.0)

[Compare
Source](https://redirect.github.com/actions/attest-build-provenance/compare/v2.2.3...v2.3.0)

#### What's Changed

- Bump `actions/attest` from 2.2.1 to 2.3.0 by
[@&#8203;bdehamer](https://redirect.github.com/bdehamer) in
[https://github.com/actions/attest-build-provenance/pull/615](https://redirect.github.com/actions/attest-build-provenance/pull/615)
    -   Updates `@sigstore/oci` from 0.4.0 to 0.5.0

**Full Changelog**:
https://github.com/actions/attest-build-provenance/compare/v2.2.3...v2.3.0

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 12:52:22 +00:00
konsti
fe6dfbc97b
Set pypa/gh-action-pypi-publish test to verbose (#13659)
See
4286993229
2025-05-26 12:42:06 +00:00
renovate[bot]
bf51b32cb6
Update Rust crate windows-result to v0.3.4 (#13529)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [windows-result](https://redirect.github.com/microsoft/windows-rs) |
workspace.dependencies | patch | `0.3.3` -> `0.3.4` |

---

> [!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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xMS4xOCIsInVwZGF0ZWRJblZlciI6IjQwLjE2LjAiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbImludGVybmFsIl19-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 14:41:46 +02:00
renovate[bot]
d393bf7886
Update docker/build-push-action action to v6.17.0 (#13653)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[docker/build-push-action](https://redirect.github.com/docker/build-push-action)
| action | minor | `v6.16.0` -> `v6.17.0` |

---

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

---

### Release Notes

<details>
<summary>docker/build-push-action (docker/build-push-action)</summary>

###
[`v6.17.0`](https://redirect.github.com/docker/build-push-action/releases/tag/v6.17.0)

[Compare
Source](https://redirect.github.com/docker/build-push-action/compare/v6.16.0...v6.17.0)

- Bump
[@&#8203;docker/actions-toolkit](https://redirect.github.com/docker/actions-toolkit)
from 0.59.0 to 0.61.0 by
[@&#8203;crazy-max](https://redirect.github.com/crazy-max) in
[https://github.com/docker/build-push-action/pull/1364](https://redirect.github.com/docker/build-push-action/pull/1364)

> \[!NOTE]
> Build record is now exported using the [`buildx history
export`](https://docs.docker.com/reference/cli/docker/buildx/history/export/)
command instead of the legacy export-build tool.

**Full Changelog**:
https://github.com/docker/build-push-action/compare/v6.16.0...v6.17.0

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 14:37:57 +02:00
renovate[bot]
853163dee5
Update astral-sh/setup-uv action to v6.1.0 (#13652)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [astral-sh/setup-uv](https://redirect.github.com/astral-sh/setup-uv) |
action | minor | `v6.0.1` -> `v6.1.0` |

---

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

---

### Release Notes

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

###
[`v6.1.0`](https://redirect.github.com/astral-sh/setup-uv/releases/tag/v6.1.0):
🌈

[Compare
Source](https://redirect.github.com/astral-sh/setup-uv/compare/v6.0.1...v6.1.0)

#### Changes

This release adds the input `server-url` which defaults to
`https://github.com`. You can set this to a custom url to control where
this action downloads the uv release from. This is useful for users of
gitea and comparable solutions.

[@&#8203;sebadevo](https://redirect.github.com/sebadevo) pointed out
that we don't invalidate the cache when the `prune-cache` input is
changed. This leads to unnessecarily big caches. The input is now used
to compute the cache key, properly invalidating the cache when it is
changed.

> \[!NOTE]\
> For most users this release will invalidate the cache once.
> You will see the known warning
[no-github-actions-cache-found-for-key](https://redirect.github.com/astral-sh/setup-uv?tab=readme-ov-file#why-do-i-see-warnings-like-no-github-actions-cache-found-for-key)
> This is expected and will only appear once.

#### 🐛 Bug fixes

- Purge cache in cache key
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;423](https://redirect.github.com/astral-sh/setup-uv/issues/423))

#### 🚀 Enhancements

- feat: support custom github url
[@&#8203;Zoupers](https://redirect.github.com/Zoupers)
([#&#8203;414](https://redirect.github.com/astral-sh/setup-uv/issues/414))

#### 🧰 Maintenance

- chore: update known versions for 0.7.7
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;422](https://redirect.github.com/astral-sh/setup-uv/issues/422))
- chore: update known versions for 0.7.6
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;415](https://redirect.github.com/astral-sh/setup-uv/issues/415))
- chore: update known versions for 0.7.5
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;412](https://redirect.github.com/astral-sh/setup-uv/issues/412))
- chore: update known versions for 0.7.4
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;410](https://redirect.github.com/astral-sh/setup-uv/issues/410))
- chore: update known versions for 0.7.3
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;405](https://redirect.github.com/astral-sh/setup-uv/issues/405))
- Fix path to known-checksums.ts
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;404](https://redirect.github.com/astral-sh/setup-uv/issues/404))
- Fix update-known-versions workflow argument
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;401](https://redirect.github.com/astral-sh/setup-uv/issues/401))
- Fix update-known-versions workflow
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;400](https://redirect.github.com/astral-sh/setup-uv/issues/400))
- Create version-manifest.json on uv release
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;399](https://redirect.github.com/astral-sh/setup-uv/issues/399))
- Run infrastructure workflows on arm runners
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;396](https://redirect.github.com/astral-sh/setup-uv/issues/396))
- chore: update known checksums for 0.7.2
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;395](https://redirect.github.com/astral-sh/setup-uv/issues/395))
- chore: update known checksums for 0.7.0
@&#8203;[github-actions\[bot\]](https://redirect.github.com/apps/github-actions)
([#&#8203;390](https://redirect.github.com/astral-sh/setup-uv/issues/390))

#### 📚 Documentation

- Add section to README explaining if packages are installed by setup-uv
[@&#8203;pirate](https://redirect.github.com/pirate)
([#&#8203;398](https://redirect.github.com/astral-sh/setup-uv/issues/398))

#### ⬆️ Dependency updates

- Bump dependencies
[@&#8203;eifinger](https://redirect.github.com/eifinger)
([#&#8203;424](https://redirect.github.com/astral-sh/setup-uv/issues/424))
- Bump typescript from 5.8.2 to 5.8.3
@&#8203;[dependabot\[bot\]](https://redirect.github.com/apps/dependabot)
([#&#8203;393](https://redirect.github.com/astral-sh/setup-uv/issues/393))

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 14:37:37 +02:00
konsti
f969417bba
Increase uv publish integration test timeout (#13658)
Sometimes we have to wait a long time for remote caches to update, see
e.g.
4289371546
2025-05-26 12:34:29 +00:00
renovate[bot]
8373261fe7
Update actions/download-artifact action to v4.3.0 (#13651)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[actions/download-artifact](https://redirect.github.com/actions/download-artifact)
| action | minor | `v4.2.1` -> `v4.3.0` |

---

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

---

### Release Notes

<details>
<summary>actions/download-artifact (actions/download-artifact)</summary>

###
[`v4.3.0`](https://redirect.github.com/actions/download-artifact/releases/tag/v4.3.0)

[Compare
Source](https://redirect.github.com/actions/download-artifact/compare/v4.2.1...v4.3.0)

#### What's Changed

- feat: implement new `artifact-ids` input by
[@&#8203;GrantBirki](https://redirect.github.com/GrantBirki) in
[https://github.com/actions/download-artifact/pull/401](https://redirect.github.com/actions/download-artifact/pull/401)
- Fix workflow example for downloading by artifact ID by
[@&#8203;joshmgross](https://redirect.github.com/joshmgross) in
[https://github.com/actions/download-artifact/pull/402](https://redirect.github.com/actions/download-artifact/pull/402)
- Prep for v4.3.0 release by
[@&#8203;robherley](https://redirect.github.com/robherley) in
[https://github.com/actions/download-artifact/pull/404](https://redirect.github.com/actions/download-artifact/pull/404)

#### New Contributors

- [@&#8203;GrantBirki](https://redirect.github.com/GrantBirki) made
their first contribution in
[https://github.com/actions/download-artifact/pull/401](https://redirect.github.com/actions/download-artifact/pull/401)

**Full Changelog**:
https://github.com/actions/download-artifact/compare/v4.2.1...v4.3.0

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 14:30:01 +02:00
renovate[bot]
9f0d83c7df
Update acj/freebsd-firecracker-action action to v0.4.0 (#13649)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[acj/freebsd-firecracker-action](https://redirect.github.com/acj/freebsd-firecracker-action)
| action | minor | `v0.3.0` -> `v0.4.0` |

---

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

---

### Release Notes

<details>
<summary>acj/freebsd-firecracker-action
(acj/freebsd-firecracker-action)</summary>

###
[`v0.4.0`](https://redirect.github.com/acj/freebsd-firecracker-action/releases/tag/v0.4.0)

[Compare
Source](https://redirect.github.com/acj/freebsd-firecracker-action/compare/v0.3.0...v0.4.0)

[Firecracker
1.12.0](https://redirect.github.com/firecracker-microvm/firecracker/releases/tag/v1.12.0)
[FreeBSD 14.3-STABLE](https://www.freebsd.org/releases/14.3R/relnotes/)

Bug fixes:

- Wait for Firecracker VM to exit before returning control to the
calling workflow

Changes:

-   Upgrade CI workflow to Ubuntu 24.04

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 13:32:46 +02:00
renovate[bot]
01622e9696
Update Rust crate jiff to v0.2.14 (#13648)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [jiff](https://redirect.github.com/BurntSushi/jiff) |
workspace.dependencies | patch | `0.2.13` -> `0.2.14` |

---

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

---

### Release Notes

<details>
<summary>BurntSushi/jiff (jiff)</summary>

###
[`v0.2.14`](https://redirect.github.com/BurntSushi/jiff/blob/HEAD/CHANGELOG.md#0214-2025-05-20)

[Compare
Source](https://redirect.github.com/BurntSushi/jiff/compare/0.2.13...0.2.14)

\===================
This release includes a smattering of bug fixes, and hopefully a small
improvement to the time it takes to compile Jiff. Also, in this release,
when
`TZ` is set to a non-empty but invalid value, Jiff will always fall back
to
`Etc/Unknown` when using `TimeZone::system()`. This differs from
previous
behavior where Jiff would, in this case, attempt to read the system's
default
time zone. This change brings Jiff into consistency with existing Unix
tooling
like `date`, and is also arguably a better failure mode. That is, when
`TZ` is
set but invalid, we shouldn't silently fall back to the default system
time
zone, but instead do something that indicates something has potentially
gone
wrong.

Enhancements:

- [#&#8203;364](https://redirect.github.com/BurntSushi/jiff/issues/364):
    Jiff now falls back to `Etc/Unknown` for invalid `TZ` values.
-   [#&#8203;379](https://redirect.github.com/BurntSushi/jiff/pull/379):
    Improve compilation times.

Bug fixes:

- [#&#8203;365](https://redirect.github.com/BurntSushi/jiff/issues/365):
Fixes a compile error in Jiff when only the `tzdb-concatenated` feature
was
    enabled.
- [#&#8203;366](https://redirect.github.com/BurntSushi/jiff/issues/366):
Fixes slow initial `Zoned::now()` in environments where
`/usr/share/zoneinfo`
    is on a very slow file system (like CI environments).
- [#&#8203;376](https://redirect.github.com/BurntSushi/jiff/issues/376):
    Avoids searching for a tzdb at `/usr/share/zoneinfo` on Windows.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 13:31:47 +02:00
renovate[bot]
1bf39e384d
Update Rust crate hyper-util to v0.1.12 (#13647)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [hyper-util](https://hyper.rs)
([source](https://redirect.github.com/hyperium/hyper-util)) |
dev-dependencies | patch | `0.1.11` -> `0.1.12` |

---

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

---

### Release Notes

<details>
<summary>hyperium/hyper-util (hyper-util)</summary>

###
[`v0.1.12`](https://redirect.github.com/hyperium/hyper-util/blob/HEAD/CHANGELOG.md#0112-2025-05-19)

[Compare
Source](https://redirect.github.com/hyperium/hyper-util/compare/v0.1.11...v0.1.12)

- Add `client::legacy::proxy::Tunnel` connector that wraps another
connector with HTTP tunneling.
- Add `client::legacy::proxy::{SocksV4, SocksV5}` connectors that wraps
another connector with SOCKS.
- Add `client::proxy::matcher::Matcher` type that can use environment
variables to match proxy rules.
- Add `server::graceful::Watcher` type that can be sent to watch a
connection in another task.
- Add `GracefulShutdown::count()` method to get number of currently
watched connections.
-   Fix missing `must_use` attributes on `Connection` futures.
-   Fix tracing span in GAI resolver that can cause panics.

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 13:30:56 +02:00
renovate[bot]
ad270c850f
Update pre-commit hook astral-sh/ruff-pre-commit to v0.11.11 (#13646)
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.11.10` -> `v0.11.11` |

---

> [!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.11.11`](https://redirect.github.com/astral-sh/ruff-pre-commit/releases/tag/v0.11.11)

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

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

</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:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuMTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW50ZXJuYWwiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 13:29:49 +02:00
Geoffrey Thomas
5b25e896b5
Update uraimo/run-on-arch-action to v3.0.1 (latest) (#13603)
This one claims in its README to resolve segfaults.

Also sync the commented-out workflow to match the uncommented ones.

## Test Plan

Checks passed in #13600 already....
2025-05-24 11:07:48 -04:00
Jo
bef128892d
Set LC_ALL=C for git when checking git worktree (#13637)
## Summary

Closes #13612

We check if the git error message includes `not a git repository` to
figure out if the path isn't a Git repo or if Git's broken. This PR sets
`LC_ALL=C` when invoking `git rev-parse --is-inside-work-tree` so that
the error message doesn’t change based on the user’s locale settings.
2025-05-24 11:05:38 -04:00
Aria Desires
0ddcc19055
Bump version to 0.7.8 (#13629) 2025-05-23 19:13:28 -04:00
Aria Desires
b93ce238a0
blocklist the linux cpython builds from 20250517 (#13617)
There is a runtime issue with some of these builds

Here is the testing I've seen ( has bug,  works):

* uv version (pbs version)
  *  uv 0.7.7 (pbs 20250521)
  *  uv 0.7.6 (pbs 20250517)
  *  uv 0.7.5 (pbs 20250409)
* os
  *  linux
  *  windows
* arch
  *  x86_64
  *  aarch64
* python version
  *  3.12
  *  3.13
  *  3.14

Fixes #13610
2025-05-23 18:15:16 -04:00
konsti
67bf3eb96c
Fix tests due to yanked configargparse (#13623)
The release of configargparse locked in the tests was yanked, we fix
this by updating the snapshots.
2025-05-23 18:43:49 +00:00
konsti
680392f03f
Update PubGrub to 06ec5a5 (#13616)
With https://github.com/pubgrub-rs/pubgrub/pull/338 merged, we update
PubGrub to 06ec5a5f59ffaeb6cf5079c6cb184467da06c9db
2025-05-23 13:51:43 +00:00
John Mumm
3758c513a4
Remove misleading line in pin documentation (#13611)
Some checks failed
CI / integration test | uv_build (push) Has been cancelled
CI / check cache | ubuntu (push) Has been cancelled
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 opensuse (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 | 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 | amazonlinux (push) Has been cancelled
CI / check system | embedded python3.10 on windows x86-64 (push) Has been cancelled
CI / benchmarks (push) Has been cancelled
The documentation did not reflect #12921.
2025-05-23 09:04:50 +02:00
konsti
30be27beb1
No GHA token for cross arch tests (#13599)
Some checks are pending
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (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 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 opensuse (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 | 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 | 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 | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
2025-05-22 21:11:38 +02:00
Aria Desires
8580b4bd2d
Bump version to 0.7.7 (#13601) 2025-05-22 14:42:26 -04:00
konsti
46bc7d3477
Build backend: Support stubs packages (#13563)
Stubs packages are different in that their name ends with `-stubs`,
their module is `<module name>-stubs` (with a dash, not the generally
legal underscore) and their modules contain a `__init__.pyi` instead of
an `__init__.py`
(https://typing.python.org/en/latest/spec/distributing.html#stub-only-packages).

We add support in the uv build backend by detecting the `-stubs` suffix.

Fixes #13546

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
2025-05-22 19:02:17 +02:00
Geoffrey Thomas
c8479574f2
Sync latest Python releases (#13593)
Some checks are pending
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (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 linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (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 opensuse (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 | 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 (push) Blocked by required conditions
Pick up python-build-standalone 20250522, in particular to fix
astral-sh/python-build-standalone#619
2025-05-22 09:21:44 -04:00
renovate[bot]
c7cabfccd7
Update markdown to v1 and fix CLI reference links (#13166)
Some checks are pending
CI / cargo test | macos (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 linux (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / integration test | github actions (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 windows trampoline | aarch64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / integration test | free-threaded on windows (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 | graalpy on windows (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
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [markdown](https://redirect.github.com/wooorm/markdown-rs) |
dependencies | major | `0.3.0` -> `1.0.0` |

---

### Release Notes

<details>
<summary>wooorm/markdown-rs (markdown)</summary>

###
[`v1.0.0`](https://redirect.github.com/wooorm/markdown-rs/releases/tag/1.0.0)

💯

Nothing changed since the last alpha.
It’s just that: this crate’s now being used a bunch and working well, so
it’s time to be stable!

</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:eyJjcmVhdGVkSW5WZXIiOiIzOS4yNTcuMyIsInVwZGF0ZWRJblZlciI6IjM5LjI1Ny4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJpbnRlcm5hbCJdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: konstin <konstin@mailbox.org>
2025-05-21 22:50:09 +02:00
Michał Górny
dbcfe9f80b
Fix version json tests to work outside git checkout (#13566)
## Summary

Fix the two version json tests to account for the possibility that uv
was built outside a git checkout (e.g. from an unpacked git archive) and
therefore does not have the commit info available. This approach uses
separate snapshots for the two cases, as suggested in discussion of pull
request #13251.

Fixes #13212

## Test Plan

1. `cargo test` in a git clone.
2. `cargo clean`, moved `.git` away, `cargo test` again.

---------

Co-authored-by: Aria Desires <aria.desires@gmail.com>
2025-05-21 15:59:39 -04:00
Aria Desires
38884da9b9
make uv version lock and sync (#13317)
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 opensuse (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 | 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 (push) Blocked by required conditions
This adopts the logic from `uv remove` for locking and syncing, as the
scope of the changes made are ultimately similar. Unlike `uv remove`
there is no support for modifying PEP723 scripts, as these are not
versioned.

In doing this the `version` command gains a truckload of args for
configuring lock/sync behaviour. Presumably most of these are passed via
settings or env files, and not of particular concern.

The most interesting additions are:

* `--frozen`: makes `uv version` work ~exactly as it did before this PR
* `--locked`: errors if the lockfile is out of date
* `--no-sync`: updates the lockfile, but doesn't run the equivalent of
`uv sync`
* `--package name`: a convenience for referring to a package in the
workspace

Note that the existing `--dry-run` flag effectively implies `--frozen` for sets and bumps.

Fixes #13254
Fixes #13548
2025-05-21 09:46:09 -04:00
konsti
cf27c077be
Remove unnecessary current dir in tests (#13561)
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 opensuse (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 | 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 (push) Blocked by required conditions
This is already done by `add_shared_options`.
2025-05-20 21:36:45 +02:00
Charlie Marsh
a47b9fd746
Revert "[docs] Fix Publishing Packages, Next = "Index"" (#13555)
Some checks are pending
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 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 opensuse (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 | 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 | 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 (push) Blocked by required conditions
Reverts astral-sh/uv#13533. I think this isn't quite right. AFAICT, this
is actually solved by upgrading our Material version.
2025-05-20 10:35:08 -04:00
Art O Cathain
1bee9320f1
Clarify adding SSH Git dependencies (#13534)
The current instructions say 

> prefix a Git-compatible URL (i.e., that you would use with git clone)
with git+.

But this does not work with the URL that Github gives you when you
choose Clone -> SSH via the UI, which is of the form
`git@github.com:astral-sh/uv.git`. If you prefix this with `git+`, i.e.

`git+git@github.com:astral-sh/uv.git`

it does not work.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-05-20 14:20:15 +00:00
Art O Cathain
9e09482647
[docs] Fix Publishing Packages, Next = "Index" (#13533)
The Next footer tab on the Publishing Packages docs page just says
"Index" which is not helpful. The page it links to is headed
"Integration guides".
2025-05-20 10:13:22 -04:00
konsti
bc7b71f269
Platform discovery is using ld.so instead ldd (#13552)
In platform discovery we're parsing the output of the ELF interpreter,
e.g., `/lib64/ld-linux-x86-64.so.2`. This file is ld, not ldd, which was
incorrectly named in the code.

An alternative is naming everything ELF interpreter instead of ld.so.
2025-05-20 15:27:22 +02:00
506 changed files with 60545 additions and 20465 deletions

View file

@ -1,4 +1,4 @@
[profile.default] [profile.default]
# Mark tests that take longer than 10s as slow. # Mark tests that take longer than 10s as slow.
# Terminate after 90s as a stop-gap measure to terminate on deadlock. # Terminate after 120s as a stop-gap measure to terminate on deadlock.
slow-timeout = { period = "10s", terminate-after = 9 } slow-timeout = { period = "10s", terminate-after = 12 }

View file

@ -54,7 +54,7 @@ jobs:
- name: "Prep README.md" - name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi run: python scripts/transform_readme.py --target pypi
- name: "Build sdist" - name: "Build sdist"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
command: sdist command: sdist
args: --out dist args: --out dist
@ -74,7 +74,7 @@ jobs:
# uv-build # uv-build
- name: "Build sdist uv-build" - name: "Build sdist uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
command: sdist command: sdist
args: --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
@ -103,7 +103,7 @@ jobs:
# uv # uv
- name: "Build wheels - x86_64" - name: "Build wheels - x86_64"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: x86_64 target: x86_64
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update
@ -133,7 +133,7 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build - x86_64" - name: "Build wheels uv-build - x86_64"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: x86_64 target: x86_64
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
@ -157,7 +157,7 @@ jobs:
# uv # uv
- name: "Build wheels - aarch64" - name: "Build wheels - aarch64"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: aarch64 target: aarch64
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update
@ -193,7 +193,7 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build - aarch64" - name: "Build wheels uv-build - aarch64"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: aarch64 target: aarch64
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
@ -231,10 +231,10 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update,windows-gui-bin
- name: "Test wheel" - name: "Test wheel"
if: ${{ !startsWith(matrix.platform.target, 'aarch64') }} if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
shell: bash shell: bash
@ -243,6 +243,7 @@ jobs:
${{ env.MODULE_NAME }} --help ${{ env.MODULE_NAME }} --help
python -m ${{ env.MODULE_NAME }} --help python -m ${{ env.MODULE_NAME }} --help
uvx --help uvx --help
uvw --help
- name: "Upload wheels" - name: "Upload wheels"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
@ -254,6 +255,7 @@ jobs:
ARCHIVE_FILE=uv-${{ matrix.platform.target }}.zip ARCHIVE_FILE=uv-${{ matrix.platform.target }}.zip
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/uv.exe 7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/uv.exe
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/uvx.exe 7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/uvx.exe
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/uvw.exe
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256 sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary" - name: "Upload binary"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
@ -265,7 +267,7 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
@ -301,7 +303,7 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
# Generally, we try to build in a target docker container. In this case however, a # Generally, we try to build in a target docker container. In this case however, a
@ -366,7 +368,7 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
manylinux: auto manylinux: auto
@ -410,19 +412,18 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
# On `aarch64`, use `manylinux: 2_28`; otherwise, use `manylinux: auto`. # On `aarch64`, use `manylinux: 2_28`; otherwise, use `manylinux: auto`.
manylinux: ${{ matrix.platform.arch == 'aarch64' && '2_28' || 'auto' }} manylinux: ${{ matrix.platform.arch == 'aarch64' && '2_28' || 'auto' }}
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel" name: "Test wheel"
with: with:
arch: ${{ matrix.platform.arch == 'arm' && 'armv6' || matrix.platform.arch }} arch: ${{ matrix.platform.arch == 'arm' && 'armv6' || matrix.platform.arch }}
distro: ${{ matrix.platform.arch == 'arm' && 'bullseye' || 'ubuntu20.04' }} distro: ${{ matrix.platform.arch == 'arm' && 'bullseye' || 'ubuntu20.04' }}
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -460,19 +461,18 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
# On `aarch64`, use `manylinux: 2_28`; otherwise, use `manylinux: auto`. # On `aarch64`, use `manylinux: 2_28`; otherwise, use `manylinux: auto`.
manylinux: ${{ matrix.platform.arch == 'aarch64' && '2_28' || 'auto' }} manylinux: ${{ matrix.platform.arch == 'aarch64' && '2_28' || 'auto' }}
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel uv-build" name: "Test wheel uv-build"
with: with:
arch: ${{ matrix.platform.arch == 'arm' && 'armv6' || matrix.platform.arch }} arch: ${{ matrix.platform.arch == 'arm' && 'armv6' || matrix.platform.arch }}
distro: ${{ matrix.platform.arch == 'arm' && 'bullseye' || 'ubuntu20.04' }} distro: ${{ matrix.platform.arch == 'arm' && 'bullseye' || 'ubuntu20.04' }}
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -509,19 +509,21 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: auto manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 # Until the llvm updates hit stable
# https://github.com/rust-lang/rust/issues/141287
rust-toolchain: nightly-2025-05-25
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
if: matrix.platform.arch != 'ppc64' if: matrix.platform.arch != 'ppc64'
name: "Test wheel" name: "Test wheel"
with: with:
arch: ${{ matrix.platform.arch }} arch: ${{ matrix.platform.arch }}
distro: ubuntu20.04 distro: ubuntu20.04
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -559,19 +561,18 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: auto manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
if: matrix.platform.arch != 'ppc64' if: matrix.platform.arch != 'ppc64'
name: "Test wheel uv-build" name: "Test wheel uv-build"
with: with:
arch: ${{ matrix.platform.arch }} arch: ${{ matrix.platform.arch }}
distro: ubuntu20.04 distro: ubuntu20.04
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -613,7 +614,7 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: auto manylinux: auto
@ -627,13 +628,12 @@ jobs:
yum install -y gcc-powerpc64-linux-gnu yum install -y gcc-powerpc64-linux-gnu
fi fi
# TODO(charlie): Re-enable testing for PPC wheels. # TODO(charlie): Re-enable testing for PPC wheels.
# - uses: uraimo/run-on-arch-action@v2 # - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
# if: matrix.platform.arch != 'ppc64' # if: matrix.platform.arch != 'ppc64'
# name: "Test wheel" # name: "Test wheel"
# with: # with:
# arch: ${{ matrix.platform.arch }} # arch: ${{ matrix.platform.arch }}
# distro: ubuntu20.04 # distro: ubuntu20.04
# githubToken: ${{ github.token }}
# install: | # install: |
# apt-get update # apt-get update
# apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 # apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -671,7 +671,7 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: auto manylinux: auto
@ -691,6 +691,103 @@ jobs:
name: wheels_uv_build-${{ matrix.platform.target }} name: wheels_uv_build-${{ matrix.platform.target }}
path: crates/uv-build/dist path: crates/uv-build/dist
# Like `linux-arm`.
linux-riscv64:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
timeout-minutes: 30
runs-on: depot-ubuntu-latest-4
strategy:
matrix:
platform:
- target: riscv64gc-unknown-linux-gnu
arch: riscv64
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
# uv
- name: "Build wheels"
uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with:
target: ${{ matrix.platform.target }}
manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --release --locked --out dist --features self-update
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel"
with:
arch: ${{ matrix.platform.arch }}
distro: ubuntu20.04
githubToken: ${{ github.token }}
install: |
apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
pip3 install -U pip
run: |
pip install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
${{ env.MODULE_NAME }} --help
# TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here.
# python -m ${{ env.MODULE_NAME }} --help
uvx --help
- name: "Upload wheels"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: wheels_uv-${{ matrix.platform.target }}
path: dist
- name: "Archive binary"
shell: bash
run: |
TARGET=${{ matrix.platform.target }}
ARCHIVE_NAME=uv-$TARGET
ARCHIVE_FILE=$ARCHIVE_NAME.tar.gz
mkdir -p $ARCHIVE_NAME
cp target/$TARGET/release/uv $ARCHIVE_NAME/uv
cp target/$TARGET/release/uvx $ARCHIVE_NAME/uvx
tar czvf $ARCHIVE_FILE $ARCHIVE_NAME
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
- name: "Upload binary"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: artifacts-${{ matrix.platform.target }}
path: |
*.tar.gz
*.sha256
# uv-build
- name: "Build wheels uv-build"
uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with:
target: ${{ matrix.platform.target }}
manylinux: auto
docker-options: ${{ matrix.platform.maturin_docker_options }}
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
- uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel uv-build"
with:
arch: ${{ matrix.platform.arch }}
distro: ubuntu20.04
githubToken: ${{ github.token }}
install: |
apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
pip3 install -U pip
run: |
pip install ${{ env.PACKAGE_NAME }}-build --no-index --find-links crates/uv-build/dist --force-reinstall
${{ env.MODULE_NAME }}-build --help
# TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here.
# python -m ${{ env.MODULE_NAME }}-build --help
- name: "Upload wheels uv-build"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: wheels_uv_build-${{ matrix.platform.target }}
path: crates/uv-build/dist
musllinux: musllinux:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }} if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -710,14 +807,14 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
manylinux: musllinux_1_1 manylinux: musllinux_1_1
args: --release --locked --out dist --features self-update args: --release --locked --out dist --features self-update
- name: "Test wheel" - name: "Test wheel"
if: matrix.target == 'x86_64-unknown-linux-musl' if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3 uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
with: with:
image: alpine:3.12 image: alpine:3.12
options: -v ${{ github.workspace }}:/io -w /io options: -v ${{ github.workspace }}:/io -w /io
@ -757,14 +854,14 @@ jobs:
# uv-build # uv-build
- name: "Build wheels uv-build" - name: "Build wheels uv-build"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
manylinux: musllinux_1_1 manylinux: musllinux_1_1
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
- name: "Test wheel uv-build" - name: "Test wheel uv-build"
if: matrix.target == 'x86_64-unknown-linux-musl' if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3 uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3
with: with:
image: alpine:3.12 image: alpine:3.12
options: -v ${{ github.workspace }}:/io -w /io options: -v ${{ github.workspace }}:/io -w /io
@ -804,19 +901,18 @@ jobs:
# uv # uv
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: musllinux_1_1 manylinux: musllinux_1_1
args: --release --locked --out dist --features self-update ${{ matrix.platform.arch == 'aarch64' && '--compatibility 2_17' || ''}} args: --release --locked --out dist --features self-update ${{ matrix.platform.arch == 'aarch64' && '--compatibility 2_17' || ''}}
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
rust-toolchain: ${{ matrix.platform.toolchain || null }} rust-toolchain: ${{ matrix.platform.toolchain || null }}
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel" name: "Test wheel"
with: with:
arch: ${{ matrix.platform.arch }} arch: ${{ matrix.platform.arch }}
distro: alpine_latest distro: alpine_latest
githubToken: ${{ github.token }}
install: | install: |
apk add python3 apk add python3
run: | run: |
@ -826,13 +922,12 @@ jobs:
# TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here. # TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here.
# .venv/bin/python -m ${{ env.MODULE_NAME }} --help # .venv/bin/python -m ${{ env.MODULE_NAME }} --help
.venv/bin/uvx --help .venv/bin/uvx --help
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel (manylinux)" name: "Test wheel (manylinux)"
if: matrix.platform.arch == 'aarch64' if: matrix.platform.arch == 'aarch64'
with: with:
arch: aarch64 arch: aarch64
distro: ubuntu20.04 distro: ubuntu20.04
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3
@ -871,19 +966,18 @@ jobs:
# uv-build # uv-build
- name: "Build wheels" - name: "Build wheels"
uses: PyO3/maturin-action@44479ae1b6b1a57f561e03add8832e62c185eb17 # v1.48.1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.platform.target }} target: ${{ matrix.platform.target }}
manylinux: musllinux_1_1 manylinux: musllinux_1_1
args: --profile minimal-size --locked ${{ matrix.platform.arch == 'aarch64' && '--compatibility 2_17' || ''}} --out crates/uv-build/dist -m crates/uv-build/Cargo.toml args: --profile minimal-size --locked ${{ matrix.platform.arch == 'aarch64' && '--compatibility 2_17' || ''}} --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
docker-options: ${{ matrix.platform.maturin_docker_options }} docker-options: ${{ matrix.platform.maturin_docker_options }}
rust-toolchain: ${{ matrix.platform.toolchain || null }} rust-toolchain: ${{ matrix.platform.toolchain || null }}
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel" name: "Test wheel"
with: with:
arch: ${{ matrix.platform.arch }} arch: ${{ matrix.platform.arch }}
distro: alpine_latest distro: alpine_latest
githubToken: ${{ github.token }}
install: | install: |
apk add python3 apk add python3
run: | run: |
@ -892,13 +986,12 @@ jobs:
.venv/bin/${{ env.MODULE_NAME }}-build --help .venv/bin/${{ env.MODULE_NAME }}-build --help
# TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here. # TODO(konsti): Enable this test on all platforms, currently `find_uv_bin` is failing to discover uv here.
# .venv/bin/python -m ${{ env.MODULE_NAME }}_build --help # .venv/bin/python -m ${{ env.MODULE_NAME }}_build --help
- uses: uraimo/run-on-arch-action@ac33288c3728ca72563c97b8b88dda5a65a84448 # v2 - uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
name: "Test wheel (manylinux)" name: "Test wheel (manylinux)"
if: matrix.platform.arch == 'aarch64' if: matrix.platform.arch == 'aarch64'
with: with:
arch: aarch64 arch: aarch64
distro: ubuntu20.04 distro: ubuntu20.04
githubToken: ${{ github.token }}
install: | install: |
apt-get update apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python-is-python3 apt-get install -y --no-install-recommends python3 python3-pip python-is-python3

View file

@ -1,11 +1,19 @@
# Build and publish a Docker image. # Build and publish Docker images.
# #
# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local # Uses Depot for multi-platform builds. Includes both a `uv` base image, which
# artifacts job within `cargo-dist`. # is just the binary in a scratch image, and a set of extra, common images with
# the uv binary installed.
# #
# TODO(charlie): Ideally, the publish step would happen as a publish job within `cargo-dist`, but # Images are built on all runs.
# sharing the built image as an artifact between jobs is challenging. #
name: "Build Docker image" # On release, assumed to run as a subworkflow of .github/workflows/release.yml;
# specifically, as a local artifacts job within `cargo-dist`. In this case,
# images are published based on the `plan`.
#
# TODO(charlie): Ideally, the publish step would happen as a publish job within
# `cargo-dist`, but sharing the built image as an artifact between jobs is
# challenging.
name: "Docker images"
on: on:
workflow_call: workflow_call:
@ -29,35 +37,67 @@ on:
- .github/workflows/build-docker.yml - .github/workflows/build-docker.yml
env: env:
UV_BASE_IMG: ghcr.io/${{ github.repository_owner }}/uv UV_GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/uv
UV_DOCKERHUB_IMAGE: docker.io/astral/uv
jobs: jobs:
docker-build: docker-plan:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }} name: plan
name: Build Docker image (ghcr.io/astral-sh/uv) for ${{ matrix.platform }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
login: ${{ steps.plan.outputs.login }}
push: ${{ steps.plan.outputs.push }}
tag: ${{ steps.plan.outputs.tag }}
action: ${{ steps.plan.outputs.action }}
steps:
- name: Set push variable
env:
DRY_RUN: ${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }}
TAG: ${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag }}
IS_LOCAL_PR: ${{ github.event.pull_request.head.repo.full_name == 'astral-sh/uv' }}
id: plan
run: |
if [ "${{ env.DRY_RUN }}" == "false" ]; then
echo "login=true" >> "$GITHUB_OUTPUT"
echo "push=true" >> "$GITHUB_OUTPUT"
echo "tag=${{ env.TAG }}" >> "$GITHUB_OUTPUT"
echo "action=build and publish" >> "$GITHUB_OUTPUT"
else
echo "login=${{ env.IS_LOCAL_PR }}" >> "$GITHUB_OUTPUT"
echo "push=false" >> "$GITHUB_OUTPUT"
echo "tag=dry-run" >> "$GITHUB_OUTPUT"
echo "action=build" >> "$GITHUB_OUTPUT"
fi
docker-publish-base:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-build') }}
name: ${{ needs.docker-plan.outputs.action }} uv
needs:
- docker-plan
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # for Depot OIDC and GHCR signing
packages: write # for GHCR image pushes
attestations: write # for GHCR attestations
environment: environment:
name: release name: ${{ needs.docker-plan.outputs.push == 'true' && 'release' || '' }}
strategy: outputs:
fail-fast: false image-tags: ${{ steps.meta.outputs.tags }}
matrix: image-annotations: ${{ steps.meta.outputs.annotations }}
platform: image-digest: ${{ steps.build.outputs.digest }}
- linux/amd64 image-version: ${{ steps.meta.outputs.version }}
- linux/arm64
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
submodules: recursive submodules: recursive
# Login to DockerHub first, to avoid rate-limiting # Login to DockerHub (when not pushing, it's to avoid rate-limiting)
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
# PRs from forks don't have access to secrets, disable this step in that case. if: ${{ needs.docker-plan.outputs.login == 'true' }}
if: ${{ github.event.pull_request.head.repo.full_name == 'astral-sh/uv' }}
with: with:
username: astralshbot username: ${{ needs.docker-plan.outputs.push == 'true' && 'astral' || 'astralshbot' }}
password: ${{ secrets.DOCKERHUB_TOKEN_RO }} password: ${{ needs.docker-plan.outputs.push == 'true' && secrets.DOCKERHUB_TOKEN_RW || secrets.DOCKERHUB_TOKEN_RO }}
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
@ -65,13 +105,15 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5
- name: Check tag consistency - name: Check tag consistency
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} if: ${{ needs.docker-plan.outputs.push == 'true' }}
run: | run: |
version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g') version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g')
if [ "${{ fromJson(inputs.plan).announcement_tag }}" != "${version}" ]; then if [ "${{ needs.docker-plan.outputs.tag }}" != "${version}" ]; then
echo "The input tag does not match the version from pyproject.toml:" >&2 echo "The input tag does not match the version from pyproject.toml:" >&2
echo "${{ fromJson(inputs.plan).announcement_tag }}" >&2 echo "${{ needs.docker-plan.outputs.tag }}" >&2
echo "${version}" >&2 echo "${version}" >&2
exit 1 exit 1
else else
@ -81,107 +123,50 @@ jobs:
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with: with:
images: ${{ env.UV_BASE_IMG }} images: |
${{ env.UV_GHCR_IMAGE }}
${{ env.UV_DOCKERHUB_IMAGE }}
# Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name # Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name
tags: | tags: |
type=raw,value=dry-run,enable=${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }} type=raw,value=dry-run,enable=${{ needs.docker-plan.outputs.push == 'false' }}
type=pep440,pattern={{ version }},value=${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }},enable=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} type=pep440,pattern={{ version }},value=${{ needs.docker-plan.outputs.tag }},enable=${{ needs.docker-plan.outputs.push }}
type=pep440,pattern={{ major }}.{{ minor }},value=${{ needs.docker-plan.outputs.tag }},enable=${{ needs.docker-plan.outputs.push }}
- name: Normalize Platform Pair (replace / with -)
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_TUPLE=${platform//\//-}" >> $GITHUB_ENV
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
- name: Build and push by digest - name: Build and push by digest
id: build id: build
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 uses: depot/build-push-action@2583627a84956d07561420dcc1d0eb1f2af3fac0 # v1.15.0
with: with:
project: 7hd4vdzmw5 # astral-sh/uv
context: . context: .
platforms: ${{ matrix.platform }} platforms: linux/amd64,linux/arm64
cache-from: type=gha,scope=uv-${{ env.PLATFORM_TUPLE }} push: ${{ needs.docker-plan.outputs.push }}
cache-to: type=gha,mode=min,scope=uv-${{ env.PLATFORM_TUPLE }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
outputs: type=image,name=${{ env.UV_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} # TODO(zanieb): Annotations are not supported by Depot yet and are ignored
annotations: ${{ steps.meta.outputs.annotations }}
- name: Export digests - name: Generate artifact attestation for base image
run: | if: ${{ needs.docker-plan.outputs.push == 'true' }}
mkdir -p /tmp/digests uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digests
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
name: digests-${{ env.PLATFORM_TUPLE }} subject-name: ${{ env.UV_GHCR_IMAGE }}
path: /tmp/digests/* subject-digest: ${{ steps.build.outputs.digest }}
if-no-files-found: error
retention-days: 1
docker-publish:
name: Publish Docker image (ghcr.io/astral-sh/uv)
runs-on: ubuntu-latest
environment:
name: release
needs:
- docker-build
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
steps:
# Login to DockerHub first, to avoid rate-limiting
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
username: astralshbot
password: ${{ secrets.DOCKERHUB_TOKEN_RO }}
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
with:
images: ${{ env.UV_BASE_IMG }}
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
tags: |
type=pep440,pattern={{ version }},value=${{ fromJson(inputs.plan).announcement_tag }}
type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
- name: Create manifest list and push
working-directory: /tmp/digests
# The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array
# The printf will expand the base image with the `<UV_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
# The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <UV_BASE_IMG>@sha256:<sha256_1> <UV_BASE_IMG>@sha256:<sha256_2> ...`
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.UV_BASE_IMG }}@sha256:%s ' *)
docker-publish-extra: docker-publish-extra:
name: Publish additional Docker image based on ${{ matrix.image-mapping }} name: ${{ needs.docker-plan.outputs.action }} ${{ matrix.image-mapping }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: environment:
name: release name: ${{ needs.docker-plan.outputs.push == 'true' && 'release' || '' }}
needs: needs:
- docker-publish - docker-plan
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} - docker-publish-base
permissions: permissions:
packages: write id-token: write # for Depot OIDC and GHCR signing
attestations: write # needed to push image attestations to the Github attestation store packages: write # for GHCR image pushes
id-token: write # needed for signing the images with GitHub OIDC Token attestations: write # for GHCR attestations
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -213,13 +198,12 @@ jobs:
- python:3.9-slim-bookworm,python3.9-bookworm-slim - python:3.9-slim-bookworm,python3.9-bookworm-slim
- python:3.8-slim-bookworm,python3.8-bookworm-slim - python:3.8-slim-bookworm,python3.8-bookworm-slim
steps: steps:
# Login to DockerHub first, to avoid rate-limiting # Login to DockerHub (when not pushing, it's to avoid rate-limiting)
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
if: ${{ needs.docker-plan.outputs.login == 'true' }}
with: with:
username: astralshbot username: ${{ needs.docker-plan.outputs.push == 'true' && 'astral' || 'astralshbot' }}
password: ${{ secrets.DOCKERHUB_TOKEN_RO }} password: ${{ needs.docker-plan.outputs.push == 'true' && secrets.DOCKERHUB_TOKEN_RW || secrets.DOCKERHUB_TOKEN_RO }}
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
@ -227,6 +211,8 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- uses: depot/setup-action@b0b1ea4f69e92ebf5dea3f8713a1b0c37b2126a5
- name: Generate Dynamic Dockerfile Tags - name: Generate Dynamic Dockerfile Tags
shell: bash shell: bash
run: | run: |
@ -238,7 +224,8 @@ jobs:
# Generate Dockerfile content # Generate Dockerfile content
cat <<EOF > Dockerfile cat <<EOF > Dockerfile
FROM ${BASE_IMAGE} FROM ${BASE_IMAGE}
COPY --from=${{ env.UV_BASE_IMG }}:latest /uv /uvx /usr/local/bin/ COPY --from=${{ env.UV_GHCR_IMAGE }}:latest /uv /uvx /usr/local/bin/
ENV UV_TOOL_BIN_DIR="/usr/local/bin"
ENTRYPOINT [] ENTRYPOINT []
CMD ["/usr/local/bin/uv"] CMD ["/usr/local/bin/uv"]
EOF EOF
@ -249,17 +236,14 @@ jobs:
# Loop through all base tags and append its docker metadata pattern to the list # Loop through all base tags and append its docker metadata pattern to the list
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
IFS=','; for TAG in ${BASE_TAGS}; do IFS=','; for TAG in ${BASE_TAGS}; do
TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ version }},suffix=-${TAG},value=${{ fromJson(inputs.plan).announcement_tag }}\n" TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ version }},suffix=-${TAG},value=${{ needs.docker-plan.outputs.tag }}\n"
TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ major }}.{{ minor }},suffix=-${TAG},value=${{ fromJson(inputs.plan).announcement_tag }}\n" TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ major }}.{{ minor }},suffix=-${TAG},value=${{ needs.docker-plan.outputs.tag }}\n"
TAG_PATTERNS="${TAG_PATTERNS}type=raw,value=${TAG}\n" TAG_PATTERNS="${TAG_PATTERNS}type=raw,value=${TAG}\n"
done done
# Remove the trailing newline from the pattern list # Remove the trailing newline from the pattern list
TAG_PATTERNS="${TAG_PATTERNS%\\n}" TAG_PATTERNS="${TAG_PATTERNS%\\n}"
# Export image cache name
echo "IMAGE_REF=${BASE_IMAGE//:/-}" >> $GITHUB_ENV
# Export tag patterns using the multiline env var syntax # Export tag patterns using the multiline env var syntax
{ {
echo "TAG_PATTERNS<<EOF" echo "TAG_PATTERNS<<EOF"
@ -274,7 +258,9 @@ jobs:
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with: with:
images: ${{ env.UV_BASE_IMG }} images: |
${{ env.UV_GHCR_IMAGE }}
${{ env.UV_DOCKERHUB_IMAGE }}
flavor: | flavor: |
latest=false latest=false
tags: | tags: |
@ -282,67 +268,84 @@ jobs:
- name: Build and push - name: Build and push
id: build-and-push id: build-and-push
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 uses: depot/build-push-action@2583627a84956d07561420dcc1d0eb1f2af3fac0 # v1.15.0
with: with:
context: . context: .
project: 7hd4vdzmw5 # astral-sh/uv
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
# We do not really need to cache here as the Dockerfile is tiny push: ${{ needs.docker-plan.outputs.push }}
#cache-from: type=gha,scope=uv-${{ env.IMAGE_REF }}
#cache-to: type=gha,mode=min,scope=uv-${{ env.IMAGE_REF }}
push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
# TODO(zanieb): Annotations are not supported by Depot yet and are ignored
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
- name: Generate artifact attestation - name: Generate artifact attestation
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 if: ${{ needs.docker-plan.outputs.push == 'true' }}
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
with: with:
subject-name: ${{ env.UV_BASE_IMG }} subject-name: ${{ env.UV_GHCR_IMAGE }}
subject-digest: ${{ steps.build-and-push.outputs.digest }} subject-digest: ${{ steps.build-and-push.outputs.digest }}
# push-to-registry is explicitly not enabled to maintain full control over the top image
# This is effectively a duplicate of `docker-publish` to make https://github.com/astral-sh/uv/pkgs/container/uv # Push annotations manually.
# show the uv base image first since GitHub always shows the last updated image digests # See `docker-annotate-base` for details.
# This works by annotating the original digests (previously non-annotated) which triggers an update to ghcr.io - name: Add annotations to images
docker-republish: if: ${{ needs.docker-plan.outputs.push == 'true' }}
name: Annotate Docker image (ghcr.io/astral-sh/uv) env:
IMAGES: "${{ env.UV_GHCR_IMAGE }} ${{ env.UV_DOCKERHUB_IMAGE }}"
DIGEST: ${{ steps.build-and-push.outputs.digest }}
TAGS: ${{ steps.meta.outputs.tags }}
ANNOTATIONS: ${{ steps.meta.outputs.annotations }}
run: |
set -x
readarray -t lines <<< "$ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done
for image in $IMAGES; do
readarray -t lines < <(grep "^${image}:" <<< "$TAGS"); tags=(); for line in "${lines[@]}"; do tags+=(-t "$line"); done
docker buildx imagetools create \
"${annotations[@]}" \
"${tags[@]}" \
"${image}@${DIGEST}"
done
# See `docker-annotate-base` for details.
- name: Export manifest digest
id: manifest-digest
if: ${{ needs.docker-plan.outputs.push == 'true' }}
env:
IMAGE: ${{ env.UV_GHCR_IMAGE }}
VERSION: ${{ steps.meta.outputs.version }}
run: |
digest="$(
docker buildx imagetools inspect \
"${IMAGE}:${VERSION}" \
--format '{{json .Manifest}}' \
| jq -r '.digest'
)"
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
# See `docker-annotate-base` for details.
- name: Generate artifact attestation
if: ${{ needs.docker-plan.outputs.push == 'true' }}
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
with:
subject-name: ${{ env.UV_GHCR_IMAGE }}
subject-digest: ${{ steps.manifest-digest.outputs.digest }}
# Annotate the base image
docker-annotate-base:
name: annotate uv
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: environment:
name: release name: ${{ needs.docker-plan.outputs.push == 'true' && 'release' || '' }}
needs: needs:
- docker-plan
- docker-publish-base
- docker-publish-extra - docker-publish-extra
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} if: ${{ needs.docker-plan.outputs.push == 'true' }}
permissions:
packages: write
attestations: write # needed to push image attestations to the Github attestation store
id-token: write # needed for signing the images with GitHub OIDC Token
steps: steps:
# Login to DockerHub first, to avoid rate-limiting
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
username: astralshbot username: astral
password: ${{ secrets.DOCKERHUB_TOKEN_RO }} password: ${{ secrets.DOCKERHUB_TOKEN_RW }}
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with:
images: ${{ env.UV_BASE_IMG }}
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
tags: |
type=pep440,pattern={{ version }},value=${{ fromJson(inputs.plan).announcement_tag }}
type=pep440,pattern={{ major }}.{{ minor }},value=${{ fromJson(inputs.plan).announcement_tag }}
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
@ -350,22 +353,37 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/ # Depot doesn't support annotating images, so we need to do so manually
- name: Create manifest list and push # afterwards. Mutating the manifest is desirable regardless, because we
working-directory: /tmp/digests # want to bump the base image to appear at the top of the list on GHCR.
# However, once annotation support is added to Depot, this step can be
# minimized to just touch the GHCR manifest.
- name: Add annotations to images
env:
IMAGES: "${{ env.UV_GHCR_IMAGE }} ${{ env.UV_DOCKERHUB_IMAGE }}"
DIGEST: ${{ needs.docker-publish-base.outputs.image-digest }}
TAGS: ${{ needs.docker-publish-base.outputs.image-tags }}
ANNOTATIONS: ${{ needs.docker-publish-base.outputs.image-annotations }}
# The readarray part is used to make sure the quoting and special characters are preserved on expansion (e.g. spaces) # The readarray part is used to make sure the quoting and special characters are preserved on expansion (e.g. spaces)
# The jq command expands the docker/metadata json "tags" array entry to `-t tag1 -t tag2 ...` for each tag in the array # The final command becomes `docker buildx imagetools create --annotation 'index:foo=1' --annotation 'index:bar=2' ... -t tag1 -t tag2 ... <IMG>@sha256:<sha256>`
# The printf will expand the base image with the `<UV_BASE_IMG>@sha256:<sha256> ...` for each sha256 in the directory
# The final command becomes `docker buildx imagetools create -t tag1 -t tag2 ... <UV_BASE_IMG>@sha256:<sha256_1> <UV_BASE_IMG>@sha256:<sha256_2> ...`
run: | run: |
readarray -t lines <<< "$DOCKER_METADATA_OUTPUT_ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done set -x
readarray -t lines <<< "$ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done
for image in $IMAGES; do
readarray -t lines < <(grep "^${image}:" <<< "$TAGS"); tags=(); for line in "${lines[@]}"; do tags+=(-t "$line"); done
docker buildx imagetools create \ docker buildx imagetools create \
"${annotations[@]}" \ "${annotations[@]}" \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ "${tags[@]}" \
$(printf '${{ env.UV_BASE_IMG }}@sha256:%s ' *) "${image}@${DIGEST}"
done
- name: Share manifest digest # Now that we've modified the manifest, we need to attest it again.
# Note we only generate an attestation for GHCR.
- name: Export manifest digest
id: manifest-digest id: manifest-digest
env:
IMAGE: ${{ env.UV_GHCR_IMAGE }}
VERSION: ${{ needs.docker-publish-base.outputs.image-version }}
# To sign the manifest, we need it's digest. Unfortunately "docker # To sign the manifest, we need it's digest. Unfortunately "docker
# buildx imagetools create" does not (yet) have a clean way of sharing # buildx imagetools create" does not (yet) have a clean way of sharing
# the digest of the manifest it creates (see docker/buildx#2407), so # the digest of the manifest it creates (see docker/buildx#2407), so
@ -377,15 +395,14 @@ jobs:
run: | run: |
digest="$( digest="$(
docker buildx imagetools inspect \ docker buildx imagetools inspect \
"${UV_BASE_IMG}:${DOCKER_METADATA_OUTPUT_VERSION}" \ "${IMAGE}:${VERSION}" \
--format '{{json .Manifest}}' \ --format '{{json .Manifest}}' \
| jq -r '.digest' | jq -r '.digest'
)" )"
echo "digest=${digest}" >> "$GITHUB_OUTPUT" echo "digest=${digest}" >> "$GITHUB_OUTPUT"
- name: Generate artifact attestation - name: Generate artifact attestation
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3 uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
with: with:
subject-name: ${{ env.UV_BASE_IMG }} subject-name: ${{ env.UV_GHCR_IMAGE }}
subject-digest: ${{ steps.manifest-digest.outputs.digest }} subject-digest: ${{ steps.manifest-digest.outputs.digest }}
# push-to-registry is explicitly not enabled to maintain full control over the top image

View file

@ -14,8 +14,9 @@ env:
CARGO_INCREMENTAL: 0 CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10 CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
PYTHON_VERSION: "3.12" PYTHON_VERSION: "3.12"
RUSTUP_MAX_RETRIES: 10
RUST_BACKTRACE: 1
jobs: jobs:
determine_changes: determine_changes:
@ -39,7 +40,7 @@ jobs:
while IFS= read -r file; do while IFS= read -r file; do
# Generated markdown and JSON files are checked during test runs. # Generated markdown and JSON files are checked during test runs.
if [[ "${file}" =~ ^docs/ && ! "${file}" =~ ^docs/reference/(cli|settings).md && ! "${file}" =~ ^docs/configuration/environment.md ]]; then if [[ "${file}" =~ ^docs/ && ! "${file}" =~ ^docs/reference/(cli|settings).md && ! "${file}" =~ ^docs/reference/environment.md ]]; then
echo "Skipping ${file} (matches docs/ pattern)" echo "Skipping ${file} (matches docs/ pattern)"
continue continue
fi fi
@ -81,7 +82,7 @@ jobs:
run: rustup component add rustfmt run: rustup component add rustfmt
- name: "Install uv" - name: "Install uv"
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- name: "rustfmt" - name: "rustfmt"
run: cargo fmt --all --check run: cargo fmt --all --check
@ -125,11 +126,11 @@ jobs:
name: "cargo clippy | ubuntu" name: "cargo clippy | ubuntu"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
save-if: ${{ github.ref == 'refs/heads/main' }} save-if: ${{ github.ref == 'refs/heads/main' }}
- name: "Check uv_build dependencies" - name: "Check uv_build dependencies"
uses: EmbarkStudios/cargo-deny-action@34899fc7ba81ca6268d5947a7a16b4649013fea1 # v2.0.11 uses: EmbarkStudios/cargo-deny-action@30f817c6f72275c6d54dc744fbca09ebc958599f # v2.0.12
with: with:
command: check bans command: check bans
manifest-path: crates/uv-build/Cargo.toml manifest-path: crates/uv-build/Cargo.toml
@ -155,7 +156,7 @@ jobs:
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }} workspaces: ${{ env.UV_WORKSPACE }}
@ -174,7 +175,7 @@ jobs:
name: "cargo dev generate-all" name: "cargo dev generate-all"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
save-if: ${{ github.ref == 'refs/heads/main' }} save-if: ${{ github.ref == 'refs/heads/main' }}
- name: "Generate all" - name: "Generate all"
@ -187,7 +188,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Install cargo shear" - name: "Install cargo shear"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-shear tool: cargo-shear
- run: cargo shear - run: cargo shear
@ -205,23 +206,26 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
run: rustup show run: rustup show
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- name: "Install required Python versions" - name: "Install required Python versions"
run: uv python install run: uv python install
- name: "Install cargo nextest" - name: "Install cargo nextest"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-nextest tool: cargo-nextest
- name: "Cargo test" - name: "Cargo test"
env:
# Retry more than default to reduce flakes in CI
UV_HTTP_RETRIES: 5
run: | run: |
cargo nextest run \ cargo nextest run \
--features python-patch \ --features python-patch \
@ -229,31 +233,35 @@ jobs:
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow --status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow
cargo-test-macos: cargo-test-macos:
timeout-minutes: 10 timeout-minutes: 15
needs: determine_changes needs: determine_changes
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} # Only run macOS tests on main without opt-in
if: ${{ contains(github.event.pull_request.labels.*.name, 'test:macos') || github.ref == 'refs/heads/main' }}
runs-on: macos-latest-xlarge # github-macos-14-aarch64-6 runs-on: macos-latest-xlarge # github-macos-14-aarch64-6
name: "cargo test | macos" name: "cargo test | macos"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
run: rustup show run: rustup show
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- name: "Install required Python versions" - name: "Install required Python versions"
run: uv python install run: uv python install
- name: "Install cargo nextest" - name: "Install cargo nextest"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-nextest tool: cargo-nextest
- name: "Cargo test" - name: "Cargo test"
env:
# Retry more than default to reduce flakes in CI
UV_HTTP_RETRIES: 5
run: | run: |
cargo nextest run \ cargo nextest run \
--no-default-features \ --no-default-features \
@ -265,7 +273,7 @@ jobs:
timeout-minutes: 15 timeout-minutes: 15
needs: determine_changes needs: determine_changes
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }}
runs-on: github-windows-2025-x86_64-16 runs-on: depot-windows-2022-16
name: "cargo test | windows" name: "cargo test | windows"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@ -278,11 +286,11 @@ jobs:
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- name: "Install required Python versions" - name: "Install required Python versions"
run: uv python install run: uv python install
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }} workspaces: ${{ env.UV_WORKSPACE }}
@ -291,13 +299,15 @@ jobs:
run: rustup show run: rustup show
- name: "Install cargo nextest" - name: "Install cargo nextest"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-nextest tool: cargo-nextest
- name: "Cargo test" - name: "Cargo test"
working-directory: ${{ env.UV_WORKSPACE }} working-directory: ${{ env.UV_WORKSPACE }}
env: env:
# Retry more than default to reduce flakes in CI
UV_HTTP_RETRIES: 5
# Avoid permission errors during concurrent tests # Avoid permission errors during concurrent tests
# See https://github.com/astral-sh/uv/issues/6940 # See https://github.com/astral-sh/uv/issues/6940
UV_LINK_MODE: copy UV_LINK_MODE: copy
@ -331,7 +341,7 @@ jobs:
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
@ -342,7 +352,7 @@ jobs:
rustup component add rust-src --target ${{ matrix.target-arch }}-pc-windows-msvc rustup component add rust-src --target ${{ matrix.target-arch }}-pc-windows-msvc
- name: "Install cargo-bloat" - name: "Install cargo-bloat"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-bloat tool: cargo-bloat
@ -387,7 +397,7 @@ jobs:
- name: Copy Git Repo to Dev Drive - name: Copy Git Repo to Dev Drive
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
@ -417,7 +427,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: crate-ci/typos@master - uses: crate-ci/typos@392b78fe18a52790c53f42456e46124f77346842 # v1.34.0
docs: docs:
timeout-minutes: 10 timeout-minutes: 10
@ -429,7 +439,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
- name: "Add SSH key" - name: "Add SSH key"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
@ -442,7 +452,7 @@ jobs:
- name: "Build docs (insiders)" - name: "Build docs (insiders)"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
run: uvx --with-requirements docs/requirements.txt mkdocs build --strict -f mkdocs.insiders.yml run: uvx --with-requirements docs/requirements-insiders.txt mkdocs build --strict -f mkdocs.insiders.yml
build-binary-linux-libc: build-binary-linux-libc:
timeout-minutes: 10 timeout-minutes: 10
@ -453,9 +463,9 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Build" - name: "Build"
run: cargo build run: cargo build
@ -469,6 +479,31 @@ jobs:
./target/debug/uvx ./target/debug/uvx
retention-days: 1 retention-days: 1
build-binary-linux-aarch64:
timeout-minutes: 10
needs: determine_changes
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }}
runs-on: github-ubuntu-24.04-aarch64-4
name: "build binary | linux aarch64"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Build"
run: cargo build
- name: "Upload binary"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: uv-linux-aarch64-${{ github.sha }}
path: |
./target/debug/uv
./target/debug/uvx
retention-days: 1
build-binary-linux-musl: build-binary-linux-musl:
timeout-minutes: 10 timeout-minutes: 10
needs: determine_changes needs: determine_changes
@ -478,14 +513,14 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- name: "Setup musl" - name: "Setup musl"
run: | run: |
sudo apt-get install musl-tools sudo apt-get install musl-tools
rustup target add x86_64-unknown-linux-musl rustup target add x86_64-unknown-linux-musl
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Build" - name: "Build"
run: cargo build --target x86_64-unknown-linux-musl --bin uv --bin uvx run: cargo build --target x86_64-unknown-linux-musl --bin uv --bin uvx
@ -508,9 +543,9 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Build" - name: "Build"
run: cargo build --bin uv --bin uvx run: cargo build --bin uv --bin uvx
@ -532,9 +567,9 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rui314/setup-mold@v1 - uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Build" - name: "Build"
run: cargo build --bin uv --bin uvx run: cargo build --bin uv --bin uvx
@ -564,7 +599,7 @@ jobs:
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }} workspaces: ${{ env.UV_WORKSPACE }}
@ -599,7 +634,7 @@ jobs:
run: | run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
workspaces: ${{ env.UV_WORKSPACE }} workspaces: ${{ env.UV_WORKSPACE }}
@ -619,8 +654,8 @@ jobs:
${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/debug/uvx.exe ${{ env.UV_WORKSPACE }}/target/aarch64-pc-windows-msvc/debug/uvx.exe
retention-days: 1 retention-days: 1
cargo-build-msrv: build-binary-msrv:
name: "cargo build (msrv)" name: "build binary | msrv"
needs: determine_changes needs: determine_changes
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }}
runs-on: github-ubuntu-24.04-x86_64-8 runs-on: github-ubuntu-24.04-x86_64-8
@ -635,8 +670,8 @@ jobs:
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
run: rustup default ${{ steps.msrv.outputs.value }} run: rustup default ${{ steps.msrv.outputs.value }}
- name: "Install mold" - name: "Install mold"
uses: rui314/setup-mold@v1 uses: rui314/setup-mold@702b1908b5edf30d71a8d1666b724e0f0c6fa035 # v1
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo +${{ steps.msrv.outputs.value }} build - run: cargo +${{ steps.msrv.outputs.value }} build
- run: ./target/debug/uv --version - run: ./target/debug/uv --version
@ -649,7 +684,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Cross build" - name: "Cross build"
run: | run: |
# Install cross from `freebsd-firecracker` # Install cross from `freebsd-firecracker`
@ -660,7 +695,7 @@ jobs:
cross build --target x86_64-unknown-freebsd cross build --target x86_64-unknown-freebsd
- name: Test in Firecracker VM - name: Test in Firecracker VM
uses: acj/freebsd-firecracker-action@4d93174d9eea32cd2b2650f964af69f8c72eaff2 # v0.3.0 uses: acj/freebsd-firecracker-action@136ca0bce2adade21e526ceb07db643ad23dd2dd # v0.5.1
with: with:
verbose: false verbose: false
checkout: false checkout: false
@ -769,6 +804,33 @@ jobs:
eval "$(./uv generate-shell-completion bash)" eval "$(./uv generate-shell-completion bash)"
eval "$(./uvx --generate-shell-completion bash)" eval "$(./uvx --generate-shell-completion bash)"
smoke-test-linux-aarch64:
timeout-minutes: 10
needs: build-binary-linux-aarch64
name: "smoke test | linux aarch64"
runs-on: github-ubuntu-24.04-aarch64-2
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-linux-aarch64-${{ github.sha }}
- name: "Prepare binary"
run: |
chmod +x ./uv
chmod +x ./uvx
- name: "Smoke test"
run: |
./uv run scripts/smoke-test
- name: "Test shell completions"
run: |
eval "$(./uv generate-shell-completion bash)"
eval "$(./uvx --generate-shell-completion bash)"
smoke-test-linux-musl: smoke-test-linux-musl:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-musl needs: build-binary-linux-musl
@ -851,7 +913,7 @@ jobs:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-windows-aarch64 needs: build-binary-windows-aarch64
name: "smoke test | windows aarch64" name: "smoke test | windows aarch64"
runs-on: github-windows-11-aarch64-4 runs-on: windows-11-arm
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@ -882,7 +944,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 - uses: conda-incubator/setup-miniconda@835234971496cad1653abb28a638a281cf32541f # v3.2.0
with: with:
miniconda-version: latest miniconda-version: latest
activate-environment: uv activate-environment: uv
@ -907,7 +969,7 @@ jobs:
./uv pip install anyio ./uv pip install anyio
integration-test-deadsnakes-39-linux: integration-test-deadsnakes-39-linux:
timeout-minutes: 5 timeout-minutes: 15
needs: build-binary-linux-libc needs: build-binary-linux-libc
name: "integration test | deadsnakes python3.9 on ubuntu" name: "integration test | deadsnakes python3.9 on ubuntu"
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -954,59 +1016,6 @@ jobs:
run: | run: |
./uv pip install -v anyio ./uv pip install -v anyio
integration-test-free-threaded-linux:
timeout-minutes: 5
needs: build-binary-linux-libc
name: "integration test | free-threaded on linux"
runs-on: ubuntu-latest
steps:
- name: "Install python3.13-nogil"
run: |
sudo add-apt-repository ppa:deadsnakes
sudo apt-get update
sudo apt-get install python3.13-nogil
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-linux-libc-${{ github.sha }}
- name: "Prepare binary"
run: chmod +x ./uv
- name: "Create a virtual environment"
run: |
./uv venv -p 3.13t --python-preference only-system
- name: "Check version"
run: |
.venv/bin/python --version
- name: "Check is free-threaded"
run: |
.venv/bin/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)"
- name: "Check install"
run: |
./uv pip install -v anyio
- name: "Install free-threaded Python via uv"
run: |
./uv python install -v 3.13t
./uv venv -p 3.13t --managed-python
- name: "Check version"
run: |
.venv/bin/python --version
- name: "Check is free-threaded"
run: |
.venv/bin/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)"
- name: "Check install"
run: |
./uv pip install -v anyio
integration-test-free-threaded-windows-x86_64: integration-test-free-threaded-windows-x86_64:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-windows-x86_64 needs: build-binary-windows-x86_64
@ -1033,7 +1042,7 @@ jobs:
- name: "Create a virtual environment (uv)" - name: "Create a virtual environment (uv)"
run: | run: |
./uv venv -p 3.13t --managed-python ./uv venv -c -p 3.13t --managed-python
- name: "Check version (uv)" - name: "Check version (uv)"
run: | run: |
@ -1052,6 +1061,96 @@ jobs:
./uv run python -c "" ./uv run python -c ""
./uv run -p 3.13t python -c "" ./uv run -p 3.13t python -c ""
integration-test-windows-aarch64-implicit:
timeout-minutes: 10
needs: build-binary-windows-aarch64
name: "integration test | aarch64 windows implicit"
runs-on: windows-11-arm
steps:
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-windows-aarch64-${{ github.sha }}
- name: "Install Python via uv (implicitly select x64)"
run: |
./uv python install -v 3.13
- name: "Create a virtual environment (stdlib)"
run: |
& (./uv python find 3.13) -m venv .venv
- name: "Check version (stdlib)"
run: |
.venv/Scripts/python --version
- name: "Create a virtual environment (uv)"
run: |
./uv venv -c -p 3.13 --managed-python
- name: "Check version (uv)"
run: |
.venv/Scripts/python --version
- name: "Check is x64"
run: |
.venv/Scripts/python -c "import sys; exit(1) if 'AMD64' not in sys.version else exit(0)"
- name: "Check install"
run: |
./uv pip install -v anyio
- name: "Check uv run"
run: |
./uv run python -c ""
./uv run -p 3.13 python -c ""
integration-test-windows-aarch64-explicit:
timeout-minutes: 10
needs: build-binary-windows-aarch64
name: "integration test | aarch64 windows explicit"
runs-on: windows-11-arm
steps:
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-windows-aarch64-${{ github.sha }}
- name: "Install Python via uv (explicitly select aarch64)"
run: |
./uv python install -v cpython-3.13-windows-aarch64-none
- name: "Create a virtual environment (stdlib)"
run: |
& (./uv python find 3.13) -m venv .venv
- name: "Check version (stdlib)"
run: |
.venv/Scripts/python --version
- name: "Create a virtual environment (uv)"
run: |
./uv venv -c -p 3.13 --managed-python
- name: "Check version (uv)"
run: |
.venv/Scripts/python --version
- name: "Check is NOT x64"
run: |
.venv/Scripts/python -c "import sys; exit(1) if 'AMD64' in sys.version else exit(0)"
- name: "Check install"
run: |
./uv pip install -v anyio
- name: "Check uv run"
run: |
./uv run python -c ""
./uv run -p 3.13 python -c ""
integration-test-pypy-linux: integration-test-pypy-linux:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-libc needs: build-binary-linux-libc
@ -1295,6 +1394,45 @@ jobs:
run: | run: |
.\uv.exe pip install anyio .\uv.exe pip install anyio
integration-test-pyodide-linux:
timeout-minutes: 10
needs: build-binary-linux-libc
name: "integration test | pyodide on ubuntu"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-linux-libc-${{ github.sha }}
- name: "Prepare binary"
run: chmod +x ./uv
- name: "Create a native virtual environment"
run: |
./uv venv venv-native -p 3.12
# We use features added in 0.30.3 but there is no known breakage in
# newer versions.
./uv pip install -p venv-native/bin/python pyodide-build==0.30.3 pip
- name: "Install pyodide interpreter"
run: |
source ./venv-native/bin/activate
pyodide xbuildenv install 0.27.5
PYODIDE_PYTHON=$(pyodide config get interpreter)
PYODIDE_INDEX=$(pyodide config get package_index)
echo "PYODIDE_PYTHON=$PYODIDE_PYTHON" >> $GITHUB_ENV
echo "PYODIDE_INDEX=$PYODIDE_INDEX" >> $GITHUB_ENV
- name: "Create pyodide virtual environment"
run: |
./uv venv -p $PYODIDE_PYTHON venv-pyodide
source ./venv-pyodide/bin/activate
./uv pip install --extra-index-url=$PYODIDE_INDEX --no-build numpy
python -c 'import numpy'
integration-test-github-actions: integration-test-github-actions:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-libc needs: build-binary-linux-libc
@ -1384,6 +1522,14 @@ jobs:
run: | run: |
./uv pip install anyio --system --python 3.13t ./uv pip install anyio --system --python 3.13t
- name: "Create a virtual environment"
run: |
./uv venv -p 3.13t --python-preference only-system
- name: "Check is free-threaded"
run: |
.venv/bin/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)"
integration-test-publish-changed: integration-test-publish-changed:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-libc needs: build-binary-linux-libc
@ -1421,8 +1567,92 @@ jobs:
done <<< "${CHANGED_FILES}" done <<< "${CHANGED_FILES}"
echo "code_any_changed=${CODE_CHANGED}" >> "${GITHUB_OUTPUT}" echo "code_any_changed=${CODE_CHANGED}" >> "${GITHUB_OUTPUT}"
integration-test-publish: integration-test-registries:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-libc
name: "integration test | registries"
runs-on: ubuntu-latest
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-test') && github.event.pull_request.head.repo.fork != true }}
environment: uv-test-registries
env:
PYTHON_VERSION: 3.12
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-linux-libc-${{ github.sha }}
- name: "Prepare binary"
run: chmod +x ./uv
- name: "Configure AWS credentials"
uses: aws-actions/configure-aws-credentials@a159d7bb5354cf786f855f2f5d1d8d768d9a08d1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: "Get AWS CodeArtifact token"
run: |
UV_TEST_AWS_TOKEN=$(aws codeartifact get-authorization-token \
--domain tests \
--domain-owner ${{ secrets.AWS_ACCOUNT_ID }} \
--region us-east-1 \
--query authorizationToken \
--output text)
echo "::add-mask::$UV_TEST_AWS_TOKEN"
echo "UV_TEST_AWS_TOKEN=$UV_TEST_AWS_TOKEN" >> $GITHUB_ENV
- name: "Authenticate with GCP"
id: "auth"
uses: "google-github-actions/auth@140bb5113ffb6b65a7e9b937a81fa96cf5064462"
with:
credentials_json: "${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}"
- name: "Set up GCP SDK"
uses: "google-github-actions/setup-gcloud@6a7c903a70c8625ed6700fa299f5ddb4ca6022e9"
- name: "Get GCP Artifact Registry token"
id: get_token
run: |
UV_TEST_GCP_TOKEN=$(gcloud auth print-access-token)
echo "::add-mask::$UV_TEST_GCP_TOKEN"
echo "UV_TEST_GCP_TOKEN=$UV_TEST_GCP_TOKEN" >> $GITHUB_ENV
- name: "Run registry tests"
run: ./uv run -p ${{ env.PYTHON_VERSION }} scripts/registries-test.py --uv ./uv --color always --all
env:
RUST_LOG: uv=debug
UV_TEST_ARTIFACTORY_TOKEN: ${{ secrets.UV_TEST_ARTIFACTORY_TOKEN }}
UV_TEST_ARTIFACTORY_URL: ${{ secrets.UV_TEST_ARTIFACTORY_URL }}
UV_TEST_ARTIFACTORY_USERNAME: ${{ secrets.UV_TEST_ARTIFACTORY_USERNAME }}
UV_TEST_AWS_URL: ${{ secrets.UV_TEST_AWS_URL }}
UV_TEST_AWS_USERNAME: aws
UV_TEST_AZURE_TOKEN: ${{ secrets.UV_TEST_AZURE_TOKEN }}
UV_TEST_AZURE_URL: ${{ secrets.UV_TEST_AZURE_URL }}
UV_TEST_AZURE_USERNAME: dummy
UV_TEST_CLOUDSMITH_TOKEN: ${{ secrets.UV_TEST_CLOUDSMITH_TOKEN }}
UV_TEST_CLOUDSMITH_URL: ${{ secrets.UV_TEST_CLOUDSMITH_URL }}
UV_TEST_CLOUDSMITH_USERNAME: ${{ secrets.UV_TEST_CLOUDSMITH_USERNAME }}
UV_TEST_GCP_URL: ${{ secrets.UV_TEST_GCP_URL }}
UV_TEST_GCP_USERNAME: oauth2accesstoken
UV_TEST_GEMFURY_TOKEN: ${{ secrets.UV_TEST_GEMFURY_TOKEN }}
UV_TEST_GEMFURY_URL: ${{ secrets.UV_TEST_GEMFURY_URL }}
UV_TEST_GEMFURY_USERNAME: ${{ secrets.UV_TEST_GEMFURY_USERNAME }}
UV_TEST_GITLAB_TOKEN: ${{ secrets.UV_TEST_GITLAB_TOKEN }}
UV_TEST_GITLAB_URL: ${{ secrets.UV_TEST_GITLAB_URL }}
UV_TEST_GITLAB_USERNAME: token
integration-test-publish:
timeout-minutes: 20
needs: integration-test-publish-changed needs: integration-test-publish-changed
name: "integration test | uv publish" name: "integration test | uv publish"
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -1470,6 +1700,7 @@ jobs:
# With this GitHub action, we can't do as rigid checks as with our custom Python script, so we publish more # With this GitHub action, we can't do as rigid checks as with our custom Python script, so we publish more
# leniently # leniently
skip-existing: "true" skip-existing: "true"
verbose: "true"
repository-url: "https://test.pypi.org/legacy/" repository-url: "https://test.pypi.org/legacy/"
packages-dir: "astral-test-pypa-gh-action/dist" packages-dir: "astral-test-pypa-gh-action/dist"
@ -1527,14 +1758,14 @@ jobs:
./uv run --no-project python -c "from built_by_uv import greet; print(greet())" ./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
# Test both `build_wheel` and `build_sdist` through uv # Test both `build_wheel` and `build_sdist` through uv
./uv venv -v ./uv venv -c -v
./uv build -v --force-pep517 scripts/packages/built-by-uv --find-links crates/uv-build/dist --offline ./uv build -v --force-pep517 scripts/packages/built-by-uv --find-links crates/uv-build/dist --offline
./uv pip install -v scripts/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps ./uv pip install -v scripts/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
./uv run --no-project python -c "from built_by_uv import greet; print(greet())" ./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
# Test both `build_wheel` and `build_sdist` through the official `build` # Test both `build_wheel` and `build_sdist` through the official `build`
rm -rf scripts/packages/built-by-uv/dist/ rm -rf scripts/packages/built-by-uv/dist/
./uv venv -v ./uv venv -c -v
./uv pip install build ./uv pip install build
# Add the uv binary to PATH for `build` to find # Add the uv binary to PATH for `build` to find
PATH="$(pwd):$PATH" UV_OFFLINE=1 UV_FIND_LINKS=crates/uv-build/dist ./uv run --no-project python -m build -v --installer uv scripts/packages/built-by-uv PATH="$(pwd):$PATH" UV_OFFLINE=1 UV_FIND_LINKS=crates/uv-build/dist ./uv run --no-project python -m build -v --installer uv scripts/packages/built-by-uv
@ -1667,38 +1898,39 @@ jobs:
- name: "Validate global Python install" - name: "Validate global Python install"
run: python scripts/check_system_python.py --uv ./uv run: python scripts/check_system_python.py --uv ./uv
system-test-opensuse: # Currently failing, see https://github.com/astral-sh/uv/issues/13811
timeout-minutes: 5 # system-test-opensuse:
needs: build-binary-linux-libc # timeout-minutes: 5
name: "check system | python on opensuse" # needs: build-binary-linux-libc
runs-on: ubuntu-latest # name: "check system | python on opensuse"
container: opensuse/tumbleweed # runs-on: ubuntu-latest
steps: # container: opensuse/tumbleweed
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # steps:
# - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Install Python" # - name: "Install Python"
run: > # run: >
until # until
zypper install -y python310 which && python3.10 -m ensurepip && mv /usr/bin/python3.10 /usr/bin/python3; # zypper install -y python310 which && python3.10 -m ensurepip && mv /usr/bin/python3.10 /usr/bin/python3;
do sleep 10; # do sleep 10;
done # done
# We retry because `zypper` can fail during remote repository updates # # We retry because `zypper` can fail during remote repository updates
# The above will not sleep forever due to the job level timeout # # The above will not sleep forever due to the job level timeout
- name: "Download binary" # - name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 # uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with: # with:
name: uv-linux-libc-${{ github.sha }} # name: uv-linux-libc-${{ github.sha }}
- name: "Prepare binary" # - name: "Prepare binary"
run: chmod +x ./uv # run: chmod +x ./uv
- name: "Print Python path" # - name: "Print Python path"
run: echo $(which python3) # run: echo $(which python3)
- name: "Validate global Python install" # - name: "Validate global Python install"
run: python3 scripts/check_system_python.py --uv ./uv # run: python3 scripts/check_system_python.py --uv ./uv
# Note: rockylinux is a 1-1 code compatible distro to rhel # Note: rockylinux is a 1-1 code compatible distro to rhel
# rockylinux mimics centos but with added maintenance stability # rockylinux mimics centos but with added maintenance stability
@ -1737,6 +1969,10 @@ jobs:
- name: "Print Python path" - name: "Print Python path"
run: echo $(which python3) run: echo $(which python3)
# Needed for building Pydantic
- name: "Install build tools"
run: dnf install -y gcc
- name: "Validate global Python install" - name: "Validate global Python install"
run: python3 scripts/check_system_python.py --uv ./uv run: python3 scripts/check_system_python.py --uv ./uv
@ -1753,7 +1989,7 @@ jobs:
python-version: "graalpy24.1" python-version: "graalpy24.1"
- name: "Download binary" - name: "Download binary"
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with: with:
name: uv-linux-libc-${{ github.sha }} name: uv-linux-libc-${{ github.sha }}
@ -1991,7 +2227,7 @@ jobs:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-windows-aarch64 needs: build-binary-windows-aarch64
name: "check system | x86-64 python3.13 on windows aarch64" name: "check system | x86-64 python3.13 on windows aarch64"
runs-on: github-windows-11-aarch64-4 runs-on: windows-11-arm
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@ -2009,6 +2245,28 @@ jobs:
- name: "Validate global Python install" - name: "Validate global Python install"
run: py -3.13 ./scripts/check_system_python.py --uv ./uv.exe run: py -3.13 ./scripts/check_system_python.py --uv ./uv.exe
system-test-windows-aarch64-aarch64-python-313:
timeout-minutes: 10
needs: build-binary-windows-aarch64
name: "check system | aarch64 python3.13 on windows aarch64"
runs-on: windows-11-arm
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.13"
architecture: "arm64"
allow-prereleases: true
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-windows-aarch64-${{ github.sha }}
- name: "Validate global Python install"
run: py -3.13-arm64 ./scripts/check_system_python.py --uv ./uv.exe
# Test our PEP 514 integration that installs Python into the Windows registry. # Test our PEP 514 integration that installs Python into the Windows registry.
system-test-windows-registry: system-test-windows-registry:
timeout-minutes: 10 timeout-minutes: 10
@ -2154,7 +2412,7 @@ jobs:
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 - uses: conda-incubator/setup-miniconda@835234971496cad1653abb28a638a281cf32541f # v3.2.0
with: with:
miniconda-version: "latest" miniconda-version: "latest"
activate-environment: uv activate-environment: uv
@ -2211,6 +2469,9 @@ jobs:
- name: "Print Python path" - name: "Print Python path"
run: echo $(which python3) run: echo $(which python3)
- name: Install build tools
run: yum install -y gcc
- name: "Validate global Python install" - name: "Validate global Python install"
run: python3 scripts/check_system_python.py --uv ./uv run: python3 scripts/check_system_python.py --uv ./uv
@ -2246,8 +2507,9 @@ jobs:
- name: "Validate embedded Python install" - name: "Validate embedded Python install"
run: python ./scripts/check_embedded_python.py --uv ./uv.exe run: python ./scripts/check_embedded_python.py --uv ./uv.exe
benchmarks: benchmarks-walltime:
runs-on: ubuntu-latest name: "benchmarks | walltime aarch64 linux"
runs-on: codspeed-macro
needs: determine_changes needs: determine_changes
if: ${{ github.repository == 'astral-sh/uv' && !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} if: ${{ github.repository == 'astral-sh/uv' && !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }}
timeout-minutes: 20 timeout-minutes: 20
@ -2255,13 +2517,13 @@ jobs:
- name: "Checkout Branch" - name: "Checkout Branch"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Install Rust toolchain" - name: "Install Rust toolchain"
run: rustup show run: rustup show
- name: "Install codspeed" - name: "Install codspeed"
uses: taiki-e/install-action@ab3728c7ba6948b9b429627f4d55a68842b27f18 # v2.50.3 uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with: with:
tool: cargo-codspeed tool: cargo-codspeed
@ -2277,7 +2539,44 @@ jobs:
run: cargo codspeed build --profile profiling --features codspeed -p uv-bench run: cargo codspeed build --profile profiling --features codspeed -p uv-bench
- name: "Run benchmarks" - name: "Run benchmarks"
uses: CodSpeedHQ/action@0010eb0ca6e89b80c88e8edaaa07cfe5f3e6664d # v3.5.0 uses: CodSpeedHQ/action@0b6e7a3d96c9d2a6057e7bcea6b45aaf2f7ce60b # v3.8.0
with:
run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }}
benchmarks-instrumented:
name: "benchmarks | instrumented"
runs-on: ubuntu-latest
needs: determine_changes
if: ${{ github.repository == 'astral-sh/uv' && !contains(github.event.pull_request.labels.*.name, 'no-test') && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }}
timeout-minutes: 20
steps:
- name: "Checkout Branch"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: "Install Rust toolchain"
run: rustup show
- name: "Install codspeed"
uses: taiki-e/install-action@a416ddeedbd372e614cc1386e8b642692f66865e # v2.57.1
with:
tool: cargo-codspeed
- name: "Install requirements and prime cache"
run: |
sudo apt-get update
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev
cargo run --bin uv -- venv --cache-dir .cache
cargo run --bin uv -- pip compile scripts/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
cargo run --bin uv -- pip compile scripts/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache
- name: "Build benchmarks"
run: cargo codspeed build --profile profiling --features codspeed -p uv-bench
- name: "Run benchmarks"
uses: CodSpeedHQ/action@0b6e7a3d96c9d2a6057e7bcea6b45aaf2f7ce60b # v3.8.0
with: with:
run: cargo codspeed run run: cargo codspeed run
token: ${{ secrets.CODSPEED_TOKEN }} token: ${{ secrets.CODSPEED_TOKEN }}

View file

@ -17,24 +17,28 @@ on:
required: true required: true
type: string type: string
permissions: {}
jobs: jobs:
mkdocs: mkdocs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
VERSION: ${{ (inputs.plan != '' && fromJson(inputs.plan).announcement_tag) || inputs.ref }}
MKDOCS_INSIDERS_SSH_KEY_EXISTS: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY != '' }} MKDOCS_INSIDERS_SSH_KEY_EXISTS: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY != '' }}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
ref: ${{ inputs.ref }} ref: ${{ inputs.ref }}
fetch-depth: 0 fetch-depth: 0
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with: with:
python-version: 3.12 python-version: 3.12
- name: "Set docs version" - name: "Set docs display name"
run: | run: |
version="${{ (inputs.plan != '' && fromJson(inputs.plan).announcement_tag) || inputs.ref }}" version="${VERSION}"
# if version is missing, use 'latest' # if version is missing, use 'latest'
if [ -z "$version" ]; then if [ -z "$version" ]; then
echo "Using 'latest' as version" echo "Using 'latest' as version"
@ -44,21 +48,20 @@ jobs:
# Use version as display name for now # Use version as display name for now
display_name="$version" display_name="$version"
echo "version=$version" >> $GITHUB_ENV echo "DISPLAY_NAME=$display_name" >> $GITHUB_ENV
echo "display_name=$display_name" >> $GITHUB_ENV
- name: "Set branch name" - name: "Set branch name"
run: | run: |
version="${{ env.version }}" version="${VERSION}"
display_name="${{ env.display_name }}" display_name="${DISPLAY_NAME}"
timestamp="$(date +%s)" timestamp="$(date +%s)"
# create branch_display_name from display_name by replacing all # create branch_display_name from display_name by replacing all
# characters disallowed in git branch names with hyphens # characters disallowed in git branch names with hyphens
branch_display_name="$(echo "$display_name" | tr -c '[:alnum:]._' '-' | tr -s '-')" branch_display_name="$(echo "$display_name" | tr -c '[:alnum:]._' '-' | tr -s '-')"
echo "branch_name=update-docs-$branch_display_name-$timestamp" >> $GITHUB_ENV echo "BRANCH_NAME=update-docs-$branch_display_name-$timestamp" >> $GITHUB_ENV
echo "timestamp=$timestamp" >> $GITHUB_ENV echo "TIMESTAMP=$timestamp" >> $GITHUB_ENV
- name: "Add SSH key" - name: "Add SSH key"
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }}
@ -84,8 +87,10 @@ jobs:
- name: "Clone docs repo" - name: "Clone docs repo"
run: | run: |
version="${{ env.version }}" version="${VERSION}"
git clone https://${{ secrets.ASTRAL_DOCS_PAT }}@github.com/astral-sh/docs.git astral-docs git clone https://${ASTRAL_DOCS_PAT}@github.com/astral-sh/docs.git astral-docs
env:
ASTRAL_DOCS_PAT: ${{ secrets.ASTRAL_DOCS_PAT }}
- name: "Copy docs" - name: "Copy docs"
run: rm -rf astral-docs/site/uv && mkdir -p astral-docs/site && cp -r site/uv astral-docs/site/ run: rm -rf astral-docs/site/uv && mkdir -p astral-docs/site && cp -r site/uv astral-docs/site/
@ -93,7 +98,7 @@ jobs:
- name: "Commit docs" - name: "Commit docs"
working-directory: astral-docs working-directory: astral-docs
run: | run: |
branch_name="${{ env.branch_name }}" branch_name="${BRANCH_NAME}"
git config user.name "astral-docs-bot" git config user.name "astral-docs-bot"
git config user.email "176161322+astral-docs-bot@users.noreply.github.com" git config user.email "176161322+astral-docs-bot@users.noreply.github.com"
@ -107,9 +112,9 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }} GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }}
run: | run: |
version="${{ env.version }}" version="${VERSION}"
display_name="${{ env.display_name }}" display_name="${DISPLAY_NAME}"
branch_name="${{ env.branch_name }}" branch_name="${BRANCH_NAME}"
# set the PR title # set the PR title
pull_request_title="Update uv documentation for $display_name" pull_request_title="Update uv documentation for $display_name"
@ -135,7 +140,7 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }} GITHUB_TOKEN: ${{ secrets.ASTRAL_DOCS_PAT }}
run: | run: |
branch_name="${{ env.branch_name }}" branch_name="${BRANCH_NAME}"
# auto-merge the PR if the build was triggered by a release. Manual builds should be reviewed by a human. # auto-merge the PR if the build was triggered by a release. Manual builds should be reviewed by a human.
# give the PR a few seconds to be created before trying to auto-merge it # give the PR a few seconds to be created before trying to auto-merge it

View file

@ -22,7 +22,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- name: "Install uv" - name: "Install uv"
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with: with:
pattern: wheels_uv-* pattern: wheels_uv-*
@ -41,7 +41,7 @@ jobs:
id-token: write id-token: write
steps: steps:
- name: "Install uv" - name: "Install uv"
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with: with:
pattern: wheels_uv_build-* pattern: wheels_uv_build-*

View file

@ -69,7 +69,7 @@ jobs:
# we specify bash to get pipefail; it guards against the `curl` command # we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0 # failing. otherwise `sh` won't catch that `curl` returned non-0
shell: bash shell: bash
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/cargo-dist/releases/download/v0.28.4/cargo-dist-installer.sh | sh" run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/cargo-dist/releases/download/v0.28.7-prerelease.2/cargo-dist-installer.sh | sh"
- name: Cache dist - name: Cache dist
uses: actions/upload-artifact@6027e3dd177782cd8ab9af838c04fd81a07f1d47 uses: actions/upload-artifact@6027e3dd177782cd8ab9af838c04fd81a07f1d47
with: with:

View file

@ -1,13 +1,43 @@
# Configures a drive for testing in CI. # Configures a drive for testing in CI.
#
# When using standard GitHub Actions runners, a `D:` drive is present and has
# similar or better performance characteristics than a ReFS dev drive. Sometimes
# using a larger runner is still more performant (e.g., when running the test
# suite) and we need to create a dev drive. This script automatically configures
# the appropriate drive.
#
# When using GitHub Actions' "larger runners", the `D:` drive is not present and
# we create a DevDrive mount on `C:`. This is purported to be more performant
# than an ReFS drive, though we did not see a change when we switched over.
#
# When using Depot runners, the underling infrastructure is EC2, which does not
# support Hyper-V. The `New-VHD` commandlet only works with Hyper-V, but we can
# create a ReFS drive using `diskpart` and `format` directory. We cannot use a
# DevDrive, as that also requires Hyper-V. The Depot runners use `D:` already,
# so we must check if it's a Depot runner first, and we use `V:` as the target
# instead.
# When not using a GitHub Actions "larger runner", the `D:` drive is present and
# has similar or better performance characteristics than a ReFS dev drive.
# Sometimes using a larger runner is still more performant (e.g., when running
# the test suite) and we need to create a dev drive. This script automatically
# configures the appropriate drive.
# Note we use `Get-PSDrive` is not sufficient because the drive letter is assigned. if ($env:DEPOT_RUNNER -eq "1") {
if (Test-Path "D:\") { Write-Output "DEPOT_RUNNER detected, setting up custom dev drive..."
# Create VHD and configure drive using diskpart
$vhdPath = "C:\uv_dev_drive.vhdx"
@"
create vdisk file="$vhdPath" maximum=20480 type=expandable
attach vdisk
create partition primary
active
assign letter=V
"@ | diskpart
# Format the drive as ReFS
format V: /fs:ReFS /q /y
$Drive = "V:"
Write-Output "Custom dev drive created at $Drive"
} elseif (Test-Path "D:\") {
# Note `Get-PSDrive` is not sufficient because the drive letter is assigned.
Write-Output "Using existing drive at D:" Write-Output "Using existing drive at D:"
$Drive = "D:" $Drive = "D:"
} else { } else {
@ -55,10 +85,8 @@ Write-Output `
"DEV_DRIVE=$($Drive)" ` "DEV_DRIVE=$($Drive)" `
"TMP=$($Tmp)" ` "TMP=$($Tmp)" `
"TEMP=$($Tmp)" ` "TEMP=$($Tmp)" `
"UV_INTERNAL__TEST_DIR=$($Tmp)" `
"RUSTUP_HOME=$($Drive)/.rustup" ` "RUSTUP_HOME=$($Drive)/.rustup" `
"CARGO_HOME=$($Drive)/.cargo" ` "CARGO_HOME=$($Drive)/.cargo" `
"UV_WORKSPACE=$($Drive)/uv" ` "UV_WORKSPACE=$($Drive)/uv" `
"PATH=$($Drive)/.cargo/bin;$env:PATH" ` "PATH=$($Drive)/.cargo/bin;$env:PATH" `
>> $env:GITHUB_ENV >> $env:GITHUB_ENV

View file

@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1 - uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
with: with:
version: "latest" version: "latest"
enable-cache: true enable-cache: true
@ -28,12 +28,20 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Sync Sysconfig Targets
run: ${{ github.workspace }}/crates/uv-dev/sync_sysconfig_targets.sh
working-directory: ./crates/uv-dev
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Create Pull Request" - name: "Create Pull Request"
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with: with:
commit-message: "Sync latest Python releases" commit-message: "Sync latest Python releases"
add-paths: | add-paths: |
crates/uv-python/download-metadata.json crates/uv-python/download-metadata.json
crates/uv-dev/src/generate_sysconfig_mappings.rs
crates/uv-python/src/sysconfig/generated_mappings.rs
branch: "sync-python-releases" branch: "sync-python-releases"
title: "Sync latest Python releases" title: "Sync latest Python releases"
body: "Automated update for Python releases." body: "Automated update for Python releases."

4
.gitignore vendored
View file

@ -3,9 +3,10 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/vendor/
debug/ debug/
target/
target-alpine/ target-alpine/
target/
# Bootstrapped Python versions # Bootstrapped Python versions
/bin/ /bin/
@ -31,6 +32,7 @@ flamegraph.svg
perf.data perf.data
perf.data.old perf.data.old
profile.json profile.json
profile.json.gz
# MkDocs # MkDocs
/site /site

View file

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

View file

@ -3,6 +3,6 @@ CHANGELOG.md
PREVIEW-CHANGELOG.md PREVIEW-CHANGELOG.md
docs/reference/cli.md docs/reference/cli.md
docs/reference/settings.md docs/reference/settings.md
docs/configuration/environment.md docs/reference/environment.md
ecosystem/home-assistant-core/LICENSE.md ecosystem/home-assistant-core/LICENSE.md
docs/guides/integration/gitlab.md docs/guides/integration/gitlab.md

View file

@ -5,7 +5,7 @@
3.9.21 3.9.21
3.8.20 3.8.20
# The following are required for packse scenarios # The following are required for packse scenarios
3.8.18 3.9.20
3.8.12 3.9.12
# The following is needed for `==3.13` request tests # The following is needed for `==3.13` request tests
3.13.0 3.13.0

View file

@ -3,257 +3,262 @@
<!-- prettier-ignore-start --> <!-- prettier-ignore-start -->
## 0.7.6 ## 0.8.4
### Python
- Add Python 3.14 on musl
- Add free-threaded Python on musl
- Add Python 3.14.0a7
- Statically link `libpython` into the interpreter on Linux for a significant performance boost
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250517)
for more details.
### Enhancements ### Enhancements
- Improve compatibility of `VIRTUAL_ENV_PROMPT` value ([#13501](https://github.com/astral-sh/uv/pull/13501)) - Improve styling of warning cause chains ([#14934](https://github.com/astral-sh/uv/pull/14934))
- Bump MSRV to 1.85 and Edition 2024 ([#13516](https://github.com/astral-sh/uv/pull/13516)) - Extend wheel filtering to Android tags ([#14977](https://github.com/astral-sh/uv/pull/14977))
- Perform wheel lockfile filtering based on platform and OS intersection ([#14976](https://github.com/astral-sh/uv/pull/14976))
### Bug fixes - Clarify messaging when a new resolution needs to be performed ([#14938](https://github.com/astral-sh/uv/pull/14938))
- Respect default extras in uv remove ([#13380](https://github.com/astral-sh/uv/pull/13380))
### Documentation
- Fix PowerShell code blocks ([#13511](https://github.com/astral-sh/uv/pull/13511))
## 0.7.5
### Bug fixes
- Support case-sensitive module discovery in the build backend ([#13468](https://github.com/astral-sh/uv/pull/13468))
- Bump Simple cache bucket to v16 ([#13498](https://github.com/astral-sh/uv/pull/13498))
- Don't error when the script is too short for the buffer ([#13488](https://github.com/astral-sh/uv/pull/13488))
- Add missing word in "script not supported" error ([#13483](https://github.com/astral-sh/uv/pull/13483))
## 0.7.4
### Enhancements
- Add more context to external errors ([#13351](https://github.com/astral-sh/uv/pull/13351))
- Align indentation of long arguments ([#13394](https://github.com/astral-sh/uv/pull/13394))
- Preserve order of dependencies which are sorted naively ([#13334](https://github.com/astral-sh/uv/pull/13334))
- Align progress bars by largest name length ([#13266](https://github.com/astral-sh/uv/pull/13266))
- Reinstall local packages in `uv add` ([#13462](https://github.com/astral-sh/uv/pull/13462))
- Rename `--raw-sources` to `--raw` ([#13348](https://github.com/astral-sh/uv/pull/13348))
- Show 'Downgraded' when `self update` is used to install an older version ([#13340](https://github.com/astral-sh/uv/pull/13340))
- Suggest `uv self update` if required uv version is newer ([#13305](https://github.com/astral-sh/uv/pull/13305))
- Add 3.14 beta images to uv Docker images ([#13390](https://github.com/astral-sh/uv/pull/13390))
- Add comma after "i.e." in Conda environment error ([#13423](https://github.com/astral-sh/uv/pull/13423))
- Be more precise in unpinned packages warning ([#13426](https://github.com/astral-sh/uv/pull/13426))
- Fix detection of sorted dependencies when include-group is used ([#13354](https://github.com/astral-sh/uv/pull/13354))
- Fix display of HTTP responses in trace logs for retry of errors ([#13339](https://github.com/astral-sh/uv/pull/13339))
- Log skip reasons during Python installation key interpreter match checks ([#13472](https://github.com/astral-sh/uv/pull/13472))
- Redact credentials when displaying URLs ([#13333](https://github.com/astral-sh/uv/pull/13333))
### Bug fixes
- Avoid erroring on `pylock.toml` dependency entries ([#13384](https://github.com/astral-sh/uv/pull/13384))
- Avoid panics for cannot-be-a-base URLs ([#13406](https://github.com/astral-sh/uv/pull/13406))
- Ensure cached realm credentials are applied if no password is found for index URL ([#13463](https://github.com/astral-sh/uv/pull/13463))
- Fix `.tgz` parsing to respect true extension ([#13382](https://github.com/astral-sh/uv/pull/13382))
- Fix double self-dependency ([#13366](https://github.com/astral-sh/uv/pull/13366))
- Reject `pylock.toml` in `uv add -r` ([#13421](https://github.com/astral-sh/uv/pull/13421))
- Retain dot-separated wheel tags during cache prune ([#13379](https://github.com/astral-sh/uv/pull/13379))
- Retain trailing comments after PEP 723 metadata block ([#13460](https://github.com/astral-sh/uv/pull/13460))
### Documentation
- Use "export" instead of "install" in `uv export` arguments ([#13430](https://github.com/astral-sh/uv/pull/13430))
- Remove extra newline ([#13461](https://github.com/astral-sh/uv/pull/13461))
### Preview features ### Preview features
- Build backend: Normalize glob paths ([#13465](https://github.com/astral-sh/uv/pull/13465)) - Add support for extending package's build dependencies with `extra-build-dependencies` ([#14735](https://github.com/astral-sh/uv/pull/14735))
- Split preview mode into separate feature flags ([#14823](https://github.com/astral-sh/uv/pull/14823))
## 0.7.3
### Enhancements
- Add `--dry-run` support to `uv self update` ([#9829](https://github.com/astral-sh/uv/pull/9829))
- Add `--show-with` to `uv tool list` to list packages included by `--with` ([#13264](https://github.com/astral-sh/uv/pull/13264))
- De-duplicate fetched index URLs ([#13205](https://github.com/astral-sh/uv/pull/13205))
- Support more zip compression formats: bzip2, lzma, xz, zstd ([#13285](https://github.com/astral-sh/uv/pull/13285))
- Add support for downloading GraalPy ([#13172](https://github.com/astral-sh/uv/pull/13172))
- Improve error message when a virtual environment Python symlink is broken ([#12168](https://github.com/astral-sh/uv/pull/12168))
- Use `fs_err` for paths in symlinking errors ([#13303](https://github.com/astral-sh/uv/pull/13303))
- Minify and embed managed Python JSON at compile time ([#12967](https://github.com/astral-sh/uv/pull/12967))
### Preview features
- Build backend: Make preview default and add configuration docs ([#12804](https://github.com/astral-sh/uv/pull/12804))
- Build backend: Allow escaping in globs ([#13313](https://github.com/astral-sh/uv/pull/13313))
- Build backend: Make builds reproducible across operating systems ([#13171](https://github.com/astral-sh/uv/pull/13171))
### Configuration ### Configuration
- Add `python-downloads-json-url` option for `uv.toml` to configure custom Python installations via JSON URL ([#12974](https://github.com/astral-sh/uv/pull/12974)) - Add support for package specific `exclude-newer` dates via `exclude-newer-package` ([#14489](https://github.com/astral-sh/uv/pull/14489))
### Bug fixes ### Bug fixes
- Check nested IO errors for retries ([#13260](https://github.com/astral-sh/uv/pull/13260)) - Avoid invalidating lockfile when path or workspace dependencies define explicit indexes ([#14876](https://github.com/astral-sh/uv/pull/14876))
- Accept `musllinux_1_0` as a valid platform tag ([#13289](https://github.com/astral-sh/uv/pull/13289)) - Copy entrypoints that have a shebang that differs in `python` vs `python3` ([#14970](https://github.com/astral-sh/uv/pull/14970))
- Fix discovery of pre-release managed Python versions in range requests ([#13330](https://github.com/astral-sh/uv/pull/13330)) - Fix incorrect file permissions in wheel packages ([#14930](https://github.com/astral-sh/uv/pull/14930))
- Respect locked script preferences in `uv run --with` ([#13283](https://github.com/astral-sh/uv/pull/13283)) - Update validation for `environments` and `required-environments` in `uv.toml` ([#14905](https://github.com/astral-sh/uv/pull/14905))
- Retry streaming downloads on broken pipe errors ([#13281](https://github.com/astral-sh/uv/pull/13281))
- Treat already-installed base environment packages as preferences in `uv run --with` ([#13284](https://github.com/astral-sh/uv/pull/13284))
- Avoid enumerating sources in errors for path Python requests ([#13335](https://github.com/astral-sh/uv/pull/13335))
- Avoid re-creating virtual environment with `--no-sync` ([#13287](https://github.com/astral-sh/uv/pull/13287))
### Documentation ### Documentation
- Remove outdated description of index strategy ([#13326](https://github.com/astral-sh/uv/pull/13326)) - Show `uv_build` in projects documentation ([#14968](https://github.com/astral-sh/uv/pull/14968))
- Update "Viewing the version" docs ([#13241](https://github.com/astral-sh/uv/pull/13241)) - Add `UV_` prefix to installer environment variables ([#14964](https://github.com/astral-sh/uv/pull/14964))
- Un-hide `uv` from `--build-backend` options ([#14939](https://github.com/astral-sh/uv/pull/14939))
- Update documentation for preview flags ([#14902](https://github.com/astral-sh/uv/pull/14902))
## 0.7.2 ## 0.8.3
### Python
- Add CPython 3.14.0rc1
See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250723) for more details.
### Enhancements ### Enhancements
- Improve trace log for retryable errors ([#13228](https://github.com/astral-sh/uv/pull/13228)) - Allow non-standard entrypoint names in `uv_build` ([#14867](https://github.com/astral-sh/uv/pull/14867))
- Use "error" instead of "warning" for self-update message ([#13229](https://github.com/astral-sh/uv/pull/13229)) - Publish riscv64 wheels to PyPI ([#14852](https://github.com/astral-sh/uv/pull/14852))
- Error when `uv version` is used with project-specific flags but no project is found ([#13203](https://github.com/astral-sh/uv/pull/13203))
### Bug fixes ### Bug fixes
- Fix incorrect virtual environment invalidation for pre-release Python versions ([#13234](https://github.com/astral-sh/uv/pull/13234)) - Avoid writing redacted credentials to tool receipt ([#14855](https://github.com/astral-sh/uv/pull/14855))
- Fix patching of `clang` in managed Python sysconfig ([#13237](https://github.com/astral-sh/uv/pull/13237)) - Respect `--with` versions over base environment versions ([#14863](https://github.com/astral-sh/uv/pull/14863))
- Respect `--project` in `uv version` ([#13230](https://github.com/astral-sh/uv/pull/13230)) - Respect credentials from all defined indexes ([#14858](https://github.com/astral-sh/uv/pull/14858))
- Fix missed stabilization of removal of registry entry during Python uninstall ([#14859](https://github.com/astral-sh/uv/pull/14859))
- Improve concurrency safety of Python downloads into cache ([#14846](https://github.com/astral-sh/uv/pull/14846))
## 0.7.1 ### Documentation
### Enhancement - Fix typos in `uv_build` reference documentation ([#14853](https://github.com/astral-sh/uv/pull/14853))
- Move the "Cargo" install method further down in docs ([#14842](https://github.com/astral-sh/uv/pull/14842))
- Add support for BLAKE2b-256 ([#13204](https://github.com/astral-sh/uv/pull/13204)) ## 0.8.2
### Bugfix ### Enhancements
- Revert fix handling of authentication when encountering redirects ([#13215](https://github.com/astral-sh/uv/pull/13215)) - Add derivation chains for dependency errors ([#14824](https://github.com/astral-sh/uv/pull/14824))
## 0.7.0 ### Configuration
This release contains various changes that improve correctness and user experience, but could break some workflows; many changes have been marked as breaking out of an abundance of caution. We expect most users to be able to upgrade without making changes. - Add `UV_INIT_BUILD_BACKEND` ([#14821](https://github.com/astral-sh/uv/pull/14821))
### Bug fixes
- Avoid reading files in the environment bin that are not entrypoints ([#14830](https://github.com/astral-sh/uv/pull/14830))
- Avoid removing empty directories when constructing virtual environments ([#14822](https://github.com/astral-sh/uv/pull/14822))
- Preserve index URL priority order when writing to pyproject.toml ([#14831](https://github.com/astral-sh/uv/pull/14831))
### Rust API
- Expose `tls_built_in_root_certs` for client ([#14816](https://github.com/astral-sh/uv/pull/14816))
### Documentation
- Archive the 0.7.x changelog ([#14819](https://github.com/astral-sh/uv/pull/14819))
## 0.8.1
### Enhancements
- Add support for `HF_TOKEN` ([#14797](https://github.com/astral-sh/uv/pull/14797))
- Allow `--config-settings-package` to apply configuration settings at the package level ([#14573](https://github.com/astral-sh/uv/pull/14573))
- Create (e.g.) `python3.13t` executables in `uv venv` ([#14764](https://github.com/astral-sh/uv/pull/14764))
- Disallow writing symlinks outside the source distribution target directory ([#12259](https://github.com/astral-sh/uv/pull/12259))
- Elide traceback when `python -m uv` in interrupted with Ctrl-C on Windows ([#14715](https://github.com/astral-sh/uv/pull/14715))
- Match `--bounds` formatting for `uv_build` bounds in `uv init` ([#14731](https://github.com/astral-sh/uv/pull/14731))
- Support `extras` and `dependency_groups` markers in PEP 508 grammar ([#14753](https://github.com/astral-sh/uv/pull/14753))
- Support `extras` and `dependency_groups` markers on `uv pip install` and `uv pip sync` ([#14755](https://github.com/astral-sh/uv/pull/14755))
- Add hint to use `uv self version` when `uv version` cannot find a project ([#14738](https://github.com/astral-sh/uv/pull/14738))
- Improve error reporting when removing Python versions from the Windows registry ([#14722](https://github.com/astral-sh/uv/pull/14722))
- Make warnings about masked `[tool.uv]` fields more precise ([#14325](https://github.com/astral-sh/uv/pull/14325))
### Preview features
- Emit JSON output in `uv sync` with `--quiet` ([#14810](https://github.com/astral-sh/uv/pull/14810))
### Bug fixes
- Allow removal of virtual environments with missing interpreters ([#14812](https://github.com/astral-sh/uv/pull/14812))
- Apply `Cache-Control` overrides to response, not request headers ([#14736](https://github.com/astral-sh/uv/pull/14736))
- Copy entry points into ephemeral environments to ensure layers are respected ([#14790](https://github.com/astral-sh/uv/pull/14790))
- Workaround Jupyter Lab application directory discovery in ephemeral environments ([#14790](https://github.com/astral-sh/uv/pull/14790))
- Enforce `requires-python` in `pylock.toml` ([#14787](https://github.com/astral-sh/uv/pull/14787))
- Fix kebab casing of `README` variants in build backend ([#14762](https://github.com/astral-sh/uv/pull/14762))
- Improve concurrency resilience of removing Python versions from the Windows registry ([#14717](https://github.com/astral-sh/uv/pull/14717))
- Retry HTTP requests on invalid data errors ([#14703](https://github.com/astral-sh/uv/pull/14703))
- Update virtual environment removal to delete `pyvenv.cfg` last ([#14808](https://github.com/astral-sh/uv/pull/14808))
- Error on unknown fields in `dependency-metadata` ([#14801](https://github.com/astral-sh/uv/pull/14801))
### Documentation
- Recommend installing `setup-uv` after `setup-python` in Github Actions integration guide ([#14741](https://github.com/astral-sh/uv/pull/14741))
- Clarify which portions of `requires-python` behavior are consistent with pip ([#14752](https://github.com/astral-sh/uv/pull/14752))
## 0.8.0
Since we released uv [0.7.0](https://github.com/astral-sh/uv/releases/tag/0.7.0) in April, we've accumulated various changes that improve correctness and user experience, but could break some workflows. This release contains those changes; many have been marked as breaking out of an abundance of caution. We expect most users to be able to upgrade without making changes.
This release also includes the stabilization of a couple `uv python install` features, which have been available under preview since late last year.
### Breaking changes ### Breaking changes
- **Update `uv version` to display and update project versions ([#12349](https://github.com/astral-sh/uv/pull/12349))** - **Install Python executables into a directory on the `PATH` ([#14626](https://github.com/astral-sh/uv/pull/14626))**
Previously, `uv version` displayed uv's version. Now, `uv version` will display or update the project's version. This interface was [heavily requested](https://github.com/astral-sh/uv/issues/6298) and, after much consideration, we decided that transitioning the top-level command was the best option. `uv python install` now installs a versioned Python executable (e.g., `python3.13`) into a directory on the `PATH` (e.g., `~/.local/bin`) by default. This behavior has been available under the `--preview` flag since [Oct 2024](https://github.com/astral-sh/uv/pull/8458). This change should not be breaking unless it shadows a Python executable elsewhere on the `PATH`.
Here's a brief example: To install unversioned executables, i.e., `python3` and `python`, use the `--default` flag. The `--default` flag has also been in preview, but is not stabilized in this release.
```console Note that these executables point to the base Python installation and only include the standard library. That means they will not include dependencies from your current project (use `uv run python` instead) and you cannot install packages into their environment (use `uvx --with <package> python` instead).
$ uv init example
Initialized project `example` at `./example`
$ cd example
$ uv version
example 0.1.0
$ uv version --bump major
example 0.1.0 => 1.0.0
$ uv version --short
1.0.0
```
If used outside of a project, uv will fallback to showing its own version still: As with tool installation, the target directory respects common variables like `XDG_BIN_HOME` and can be overridden with a `UV_PYTHON_BIN_DIR` variable.
```console You can opt out of this behavior with `uv python install --no-bin` or `UV_PYTHON_INSTALL_BIN=0`.
$ uv version
warning: failed to read project: No `pyproject.toml` found in current directory or any parent directory
running `uv self version` for compatibility with old `uv version` command.
this fallback will be removed soon, pass `--preview` to make this an error.
uv 0.7.0 (4433f41c9 2025-04-29) See the [documentation on installing Python executables](https://docs.astral.sh/uv/concepts/python-versions/#installing-python-executables) for more details.
``` - **Register Python versions with the Windows Registry ([#14625](https://github.com/astral-sh/uv/pull/14625))**
As described in the warning, `--preview` can be used to error instead: `uv python install` now registers the installed Python version with the Windows Registry as specified by [PEP 514](https://peps.python.org/pep-0514/). This allows using uv installed Python versions via the `py` launcher. This behavior has been available under the `--preview` flag since [Jan 2025](https://github.com/astral-sh/uv/pull/10634). This change should not be breaking, as using the uv Python versions with `py` requires explicit opt in.
```console You can opt out of this behavior with `uv python install --no-registry` or `UV_PYTHON_INSTALL_REGISTRY=0`.
$ uv version --preview - **Prompt before removing an existing directory in `uv venv` ([#14309](https://github.com/astral-sh/uv/pull/14309))**
error: No `pyproject.toml` found in current directory or any parent directory
```
The previous functionality of `uv version` was moved to `uv self version`. Previously, `uv venv` would remove an existing virtual environment without confirmation. While this is consistent with the behavior of project commands (e.g., `uv sync`), it's surprising to users that are using imperative workflows (i.e., `uv pip`). Now, `uv venv` will prompt for confirmation before removing an existing virtual environment. **If not in an interactive context, uv will still remove the virtual environment for backwards compatibility. However, this behavior is likely to change in a future release.**
- **Avoid fallback to subsequent indexes on authentication failure ([#12805](https://github.com/astral-sh/uv/pull/12805))**
When using the `first-index` strategy (the default), uv will stop searching indexes for a package once it is found on a single index. Previously, uv considered a package as "missing" from an index during authentication failures, such as an HTTP 401 or HTTP 403 (normally, missing packages are represented by an HTTP 404). This behavior was motivated by unusual responses from some package indexes, but reduces the safety of uv's index strategy when authentication fails. Now, uv will consider an authentication failure as a stop-point when searching for a package across indexes. The `index.ignore-error-codes` option can be used to recover the existing behavior, e.g.: The behavior for other commands (e.g., `uv sync`) is unchanged.
You can opt out of this behavior by setting `UV_VENV_CLEAR=1` or passing the `--clear` flag.
- **Validate that discovered interpreters meet the Python preference ([#7934](https://github.com/astral-sh/uv/pull/7934))**
uv allows opting out of its managed Python versions with the `--no-managed-python` and `python-preference` options.
Previously, uv would not enforce this option for Python interpreters discovered on the `PATH`. For example, if a symlink to a managed Python interpreter was created, uv would allow it to be used even if `--no-managed-python` was provided. Now, uv ignores Python interpreters that do not match the Python preference *unless* they are in an active virtual environment or are explicitly requested, e.g., with `--python /path/to/python3.13`.
Similarly, uv would previously not invalidate existing project environments if they did not match the Python preference. Now, uv will invalidate and recreate project environments when the Python preference changes.
You can opt out of this behavior by providing the explicit path to the Python interpreter providing `--managed-python` / `--no-managed-python` matching the interpreter you want.
- **Install dependencies without build systems when they are `path` sources ([#14413](https://github.com/astral-sh/uv/pull/14413))**
When working on a project, uv uses the [presence of a build system](https://docs.astral.sh/uv/concepts/projects/config/#build-systems) to determine if it should be built and installed into the environment. However, when a project is a dependency of another project, it can be surprising for the dependency to be missing from the environment.
Previously, uv would not build and install dependencies with [`path` sources](https://docs.astral.sh/uv/concepts/projects/dependencies/#path) unless they declared a build system or set `tool.uv.package = true`. Now, dependencies with `path` sources are built and installed regardless of the presence of a build system. If a build system is not present, the `setuptools.build_meta:__legacy__ ` backend will be used (per [PEP 517](https://peps.python.org/pep-0517/#source-trees)).
You can opt out of this behavior by setting `package = false` in the source declaration, e.g.:
```toml ```toml
[[tool.uv.index]] [tool.uv.sources]
name = "pytorch" foo = { path = "./foo", package = false }
url = "https://download.pytorch.org/whl/cpu"
ignore-error-codes = [401, 403]
``` ```
Since PyTorch's indexes always return a HTTP 403 for missing packages, uv special-cases indexes on the `pytorch.org` domain to ignore that error code by default. Or, by setting `tool.uv.package = false` in the dependent `pyproject.toml`.
- **Require the command in `uvx <name>` to be available in the Python environment ([#11603](https://github.com/astral-sh/uv/pull/11603))**
Previously, `uvx` would attempt to execute a command even if it was not provided by a Python package. For example, if we presume `foo` is an empty Python package which provides no command, `uvx foo` would invoke the `foo` command on the `PATH` (if present). Now, uv will error early if the `foo` executable is not provided by the requested Python package. This check is not enforced when `--from` is used, so patterns like `uvx --from foo bash -c "..."` are still valid. uv also still allows `uvx foo` where the `foo` executable is provided by a dependency of `foo` instead of `foo` itself, as this is fairly common for packages which depend on a dedicated package for their command-line interface. See the documentation on [virtual dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/#virtual-dependencies) for details.
- **Use index URL instead of package URL for keyring credential lookups ([#12651](https://github.com/astral-sh/uv/pull/12651))** - **Install dependencies without build systems when they are workspace members ([#14663](https://github.com/astral-sh/uv/pull/14663))**
When determining credentials for querying a package URL, uv previously sent the full URL to the `keyring` command. However, some keyring plugins expect to receive the *index URL* (which is usually a parent of the package URL). Now, uv requests credentials for the index URL instead. This behavior matches `pip`. As described above for dependencies with `path` sources, uv previously would not build and install workspace members that did not declare a build system. Now, uv will build and install workspace members that are a dependency of *another* workspace member regardless of the presence of a build system. The behavior is unchanged for workspace members that are not included in the `project.dependencies`, `project.optional-dependencies`, or `dependency-groups` tables of another workspace member.
- **Remove `--version` from subcommands ([#13108](https://github.com/astral-sh/uv/pull/13108))**
Previously, uv allowed the `--version` flag on arbitrary subcommands, e.g., `uv run --version`. However, the `--version` flag is useful for other operations since uv is a package manager. Consequently, we've removed the `--version` flag from subcommands — it is only available as `uv --version`. You can opt out of this behavior by setting `tool.uv.package = false` in the workspace member's `pyproject.toml`.
- **Omit Python 3.7 downloads from managed versions ([#13022](https://github.com/astral-sh/uv/pull/13022))**
Python 3.7 is EOL and not formally supported by uv; however, Python 3.7 was previously available for download on a subset of platforms. See the documentation on [virtual dependencies](https://docs.astral.sh/uv/concepts/projects/dependencies/#virtual-dependencies) for details.
- **Reject non-PEP 751 TOML files in install, compile, and export commands ([#13120](https://github.com/astral-sh/uv/pull/13120), [#13119](https://github.com/astral-sh/uv/pull/13119))** - **Bump `--python-platform linux` to `manylinux_2_28` ([#14300](https://github.com/astral-sh/uv/pull/14300))**
Previously, uv treated arbitrary `.toml` files passed to commands (e.g., `uv pip install -r foo.toml` or `uv pip compile -o foo.toml`) as `requirements.txt`-formatted files. Now, uv will error instead. If using PEP 751 lockfiles, use the standardized format for custom names instead, e.g., `pylock.foo.toml`. uv allows performing [platform-specific resolution](https://docs.astral.sh/uv/concepts/resolution/#platform-specific-resolution) for explicit targets and provides short aliases, e.g., `linux`, for common targets.
- **Ignore arbitrary Python requests in version files ([#12909](https://github.com/astral-sh/uv/pull/12909))**
uv allows arbitrary strings to be used for Python version requests, in which they are treated as an executable name to search for in the `PATH`. However, using this form of request in `.python-version` files is non-standard and conflicts with `pyenv-virtualenv` which writes environment names to `.python-version` files. In this release, uv will now ignore requests that are arbitrary strings when found in `.python-version` files. Previously, the default target for `--python-platform linux` was `manylinux_2_17`, which is compatible with most Linux distributions from 2014 or newer. We now default to `manylinux_2_28`, which is compatible with most Linux distributions from 2019 or newer. This change follows the lead of other tools, such as `cibuildwheel`, which changed their default to `manylinux_2_28` in [Mar 2025](https://github.com/pypa/cibuildwheel/pull/2330).
- **Error on unknown dependency object specifiers ([12811](https://github.com/astral-sh/uv/pull/12811))**
The `[dependency-groups]` entries can include "object specifiers", e.g. `set-phasers-to = ...` in: This change only affects users requesting a specific target platform. Otherwise, uv detects the `manylinux` target from your local glibc version.
```toml You can opt out of this behavior by using `--python-platform x86_64-manylinux_2_17` instead.
[dependency-groups] - **Remove `uv version` fallback ([#14161](https://github.com/astral-sh/uv/pull/14161))**
foo = ["pyparsing"]
bar = [{set-phasers-to = "stun"}]
```
However, the only current spec-compliant object specifier is `include-group`. Previously, uv would ignore unknown object specifiers. Now, uv will error. In [Apr 2025](https://github.com/astral-sh/uv/pull/12349), uv changed the `uv version` command to an interface for viewing and updating the version of the current project. However, when outside a project, `uv version` would continue to display uv's version for backwards compatibility. Now, when used outside of a project, `uv version` will fail.
- **Make `--frozen` and `--no-sources` conflicting options ([#12671](https://github.com/astral-sh/uv/pull/12671))**
Using `--no-sources` always requires a new resolution and `--frozen` will always fail when used with it. Now, this conflict is encoded in the CLI options for clarity. You cannot opt out of this behavior. Use `uv self version` instead.
- **Treat empty `UV_PYTHON_INSTALL_DIR` and `UV_TOOL_DIR` as unset ([#12907](https://github.com/astral-sh/uv/pull/12907), [#12905](https://github.com/astral-sh/uv/pull/12905))** - **Require `--global` for removal of the global Python pin ([#14169](https://github.com/astral-sh/uv/pull/14169))**
Previously, these variables were treated as set to the current working directory when set to an empty string. Now, uv will ignore these variables when empty. This matches uv's behavior for other environment variables which configure directories. Previously, `uv python pin --rm` would allow you to remove the global Python pin without opt in. Now, uv requires the `--global` flag to remove the global Python pin.
### Enhancements You cannot opt out of this behavior. Use the `--global` flag instead.
- **Support conflicting editable settings across groups ([#14197](https://github.com/astral-sh/uv/pull/14197))**
- Disallow mixing requirements across PyTorch indexes ([#13179](https://github.com/astral-sh/uv/pull/13179)) Previously, uv would always treat a package as editable if any requirement requested it as editable. However, this prevented users from declaring `path` sources that toggled the `editable` setting across dependency groups. Now, uv allows declaring different `editable` values for conflicting groups. However, if a project includes a path dependency twice, once with `editable = true` and once without any editable annotation, those are now considered conflicting, and uv will exit with an error.
- Add optional managed Python archive download cache ([#12175](https://github.com/astral-sh/uv/pull/12175))
- Add `poetry-core` as a `uv init` build backend option ([#12781](https://github.com/astral-sh/uv/pull/12781))
- Show tag hints when failing to find a compatible wheel in `pylock.toml` ([#13136](https://github.com/astral-sh/uv/pull/13136))
- Report Python versions in `pyvenv.cfg` version mismatch ([#13027](https://github.com/astral-sh/uv/pull/13027))
### Bug fixes You cannot opt out of this behavior. Use consistent `editable` settings or [mark groups as conflicting](https://docs.astral.sh/uv/concepts/projects/config/#conflicting-dependencies).
- **Make `uv_build` the default build backend in `uv init` ([#14661](https://github.com/astral-sh/uv/pull/14661))**
- Avoid erroring on omitted wheel-only packages in `pylock.toml` ([#13132](https://github.com/astral-sh/uv/pull/13132)) The uv build backend (`uv_build`) was [stabilized in uv 0.7.19](https://github.com/astral-sh/uv/releases/tag/0.7.19). Now, it is the default build backend for `uv init --package` and `uv init --lib`. Previously, `hatchling` was the default build backend. A build backend is still not used without opt-in in `uv init`, but we expect to change this in a future release.
- Fix display name for `uvx --version` ([#13109](https://github.com/astral-sh/uv/pull/13109))
- Restore handling of authentication when encountering redirects ([#13050](https://github.com/astral-sh/uv/pull/13050))
- Respect build options (`--no-binary` et al) in `pylock.toml` ([#13134](https://github.com/astral-sh/uv/pull/13134))
- Use `upload-time` rather than `upload_time` in `uv.lock` ([#13176](https://github.com/astral-sh/uv/pull/13176))
### Documentation You can opt out of this behavior with `uv init --build-backend hatchling`.
- **Set default `UV_TOOL_BIN_DIR` on Docker images ([#13391](https://github.com/astral-sh/uv/pull/13391))**
- Changed `fish` completions append `>>` to overwrite `>` ([#13130](https://github.com/astral-sh/uv/pull/13130)) Previously, `UV_TOOL_BIN_DIR` was not set in Docker images which meant that `uv tool install` did not install tools into a directory on the `PATH` without additional configuration. Now, `UV_TOOL_BIN_DIR` is set to `/usr/local/bin` in all Docker derived images.
- Add `pylock.toml` mentions where relevant ([#13115](https://github.com/astral-sh/uv/pull/13115))
- Add ROCm example to the PyTorch guide ([#13200](https://github.com/astral-sh/uv/pull/13200)) When the default image user is overridden (e.g. `USER <UID>`) with a less privileged user, this may cause `uv tool install` to fail.
- Upgrade PyTorch guide to CUDA 12.8 and PyTorch 2.7 ([#13199](https://github.com/astral-sh/uv/pull/13199))
You can opt out of this behavior by setting an alternative `UV_TOOL_BIN_DIR`.
- **Update `--check` to return an exit code of 1 ([#14167](https://github.com/astral-sh/uv/pull/14167))**
uv uses an exit code of 1 to indicate a "successful failure" and an exit code of 2 to indicate an "error".
Previously, `uv lock --check` and `uv sync --check` would exit with a code of 2 when the lockfile or environment were outdated. Now, uv will exit with a code of 1.
You cannot opt out of this behavior.
- **Use an ephemeral environment for `uv run --with` invocations ([#14447](https://github.com/astral-sh/uv/pull/14447))**
When using `uv run --with`, uv layers the requirements requested using `--with` into another virtual environment and caches it. Previously, uv would invoke the Python interpreter in this layered environment. However, this allows poisoning the cached environment and introduces race conditions for concurrent invocations. Now, uv will layer *another* empty virtual environment on top of the cached environment and invoke the Python interpreter there. This should only cause breakage in cases where the environment is being inspected at runtime.
You cannot opt out of this behavior.
- **Restructure the `uv venv` command output and exit codes ([#14546](https://github.com/astral-sh/uv/pull/14546))**
Previously, uv used `miette` to format the `uv venv` output. However, this was inconsistent with most of the uv CLI. Now, the output is a little different and the exit code has switched from 1 to 2 for some error cases.
You cannot opt out of this behavior.
- **Default to `--workspace` when adding subdirectories ([#14529](https://github.com/astral-sh/uv/pull/14529))**
When using `uv add` to add a subdirectory in a workspace, uv now defaults to adding the target as a workspace member.
You can opt out of this behavior by providing `--no-workspace`.
- **Add missing validations for disallowed `uv.toml` fields ([#14322](https://github.com/astral-sh/uv/pull/14322))**
uv does not allow some settings in the `uv.toml`. Previously, some settings were silently ignored when present in the `uv.toml`. Now, uv will error.
You cannot opt out of this behavior. Use `--no-config` or remove the invalid settings.
### Configuration
- Add support for toggling Python bin and registry install options via env vars ([#14662](https://github.com/astral-sh/uv/pull/14662))
## 0.7.x
See [changelogs/0.7.x](./changelogs/0.7.x.md)
## 0.6.x ## 0.6.x

View file

@ -74,7 +74,7 @@ system
just resolving requirements. To prevent this, there's a Docker container you can run commands in: just resolving requirements. To prevent this, there's a Docker container you can run commands in:
```console ```console
$ docker buildx build -t uv-builder -f builder.dockerfile --load . $ docker build -t uv-builder -f crates/uv-dev/builder.dockerfile --load .
# Build for musl to avoid glibc errors, might not be required with your OS version # Build for musl to avoid glibc errors, might not be required with your OS version
cargo build --target x86_64-unknown-linux-musl --profile profiling cargo build --target x86_64-unknown-linux-musl --profile profiling
docker run --rm -it -v $(pwd):/app uv-builder /app/target/x86_64-unknown-linux-musl/profiling/uv-dev resolve-many --cache-dir /app/cache-docker /app/scripts/popular_packages/pypi_10k_most_dependents.txt docker run --rm -it -v $(pwd):/app uv-builder /app/target/x86_64-unknown-linux-musl/profiling/uv-dev resolve-many --cache-dir /app/cache-docker /app/scripts/popular_packages/pypi_10k_most_dependents.txt
@ -165,6 +165,13 @@ After making changes to the documentation, format the markdown files with:
npx prettier --prose-wrap always --write "**/*.md" npx prettier --prose-wrap always --write "**/*.md"
``` ```
Note that the command above requires Node.js and npm to be installed on your system. As an
alternative, you can run this command using Docker:
```console
$ docker run --rm -v .:/src/ -w /src/ node:alpine npx prettier --prose-wrap always --write "**/*.md"
```
## Releases ## Releases
Releases can only be performed by Astral team members. Releases can only be performed by Astral team members.

1726
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ resolver = "2"
[workspace.package] [workspace.package]
edition = "2024" edition = "2024"
rust-version = "1.85" rust-version = "1.86"
homepage = "https://pypi.org/project/uv/" homepage = "https://pypi.org/project/uv/"
documentation = "https://pypi.org/project/uv/" documentation = "https://pypi.org/project/uv/"
repository = "https://github.com/astral-sh/uv" repository = "https://github.com/astral-sh/uv"
@ -49,6 +49,7 @@ uv-once-map = { path = "crates/uv-once-map" }
uv-options-metadata = { path = "crates/uv-options-metadata" } uv-options-metadata = { path = "crates/uv-options-metadata" }
uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] } uv-pep440 = { path = "crates/uv-pep440", features = ["tracing", "rkyv", "version-ranges"] }
uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] } uv-pep508 = { path = "crates/uv-pep508", features = ["non-pep508-extensions"] }
uv-platform = { path = "crates/uv-platform" }
uv-platform-tags = { path = "crates/uv-platform-tags" } uv-platform-tags = { path = "crates/uv-platform-tags" }
uv-publish = { path = "crates/uv-publish" } uv-publish = { path = "crates/uv-publish" }
uv-pypi-types = { path = "crates/uv-pypi-types" } uv-pypi-types = { path = "crates/uv-pypi-types" }
@ -75,12 +76,13 @@ uv-workspace = { path = "crates/uv-workspace" }
anstream = { version = "0.6.15" } anstream = { version = "0.6.15" }
anyhow = { version = "1.0.89" } anyhow = { version = "1.0.89" }
arcstr = { version = "1.2.0" } arcstr = { version = "1.2.0" }
astral-tokio-tar = { version = "0.5.1" } arrayvec = { version = "0.7.6" }
astral-tokio-tar = { version = "0.5.2" }
async-channel = { version = "2.3.1" } async-channel = { version = "2.3.1" }
async-compression = { version = "0.4.12", features = ["bzip2", "gzip", "xz", "zstd"] } async-compression = { version = "0.4.12", features = ["bzip2", "gzip", "xz", "zstd"] }
async-trait = { version = "0.1.82" } async-trait = { version = "0.1.82" }
async_http_range_reader = { version = "0.9.1" } async_http_range_reader = { version = "0.9.1" }
async_zip = { git = "https://github.com/charliermarsh/rs-async-zip", rev = "c909fda63fcafe4af496a07bfda28a5aae97e58d", features = ["bzip2", "deflate", "lzma", "tokio", "xz", "zstd"] } async_zip = { git = "https://github.com/astral-sh/rs-async-zip", rev = "c909fda63fcafe4af496a07bfda28a5aae97e58d", features = ["bzip2", "deflate", "lzma", "tokio", "xz", "zstd"] }
axoupdater = { version = "0.9.0", default-features = false } axoupdater = { version = "0.9.0", default-features = false }
backon = { version = "1.3.0" } backon = { version = "1.3.0" }
base64 = { version = "0.22.1" } base64 = { version = "0.22.1" }
@ -92,7 +94,7 @@ cargo-util = { version = "0.2.14" }
clap = { version = "4.5.17", features = ["derive", "env", "string", "wrap_help"] } clap = { version = "4.5.17", features = ["derive", "env", "string", "wrap_help"] }
clap_complete_command = { version = "0.6.1" } clap_complete_command = { version = "0.6.1" }
configparser = { version = "3.1.0" } configparser = { version = "3.1.0" }
console = { version = "0.15.11", default-features = false } console = { version = "0.16.0", default-features = false, features = ["std"] }
csv = { version = "1.3.0" } csv = { version = "1.3.0" }
ctrlc = { version = "3.4.5" } ctrlc = { version = "3.4.5" }
dashmap = { version = "6.1.0" } dashmap = { version = "6.1.0" }
@ -109,14 +111,14 @@ futures = { version = "0.3.30" }
glob = { version = "0.3.1" } glob = { version = "0.3.1" }
globset = { version = "0.4.15" } globset = { version = "0.4.15" }
globwalk = { version = "0.9.1" } globwalk = { version = "0.9.1" }
goblin = { version = "0.9.0", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] } goblin = { version = "0.10.0", default-features = false, features = ["std", "elf32", "elf64", "endian_fd"] }
hashbrown = { version = "0.15.1" } hashbrown = { version = "0.15.1" }
hex = { version = "0.4.3" } hex = { version = "0.4.3" }
home = { version = "0.5.9" } home = { version = "0.5.9" }
html-escape = { version = "0.2.13" } html-escape = { version = "0.2.13" }
http = { version = "1.1.0" } http = { version = "1.1.0" }
indexmap = { version = "2.5.0" } indexmap = { version = "2.5.0" }
indicatif = { version = "0.17.8" } indicatif = { version = "0.18.0" }
indoc = { version = "2.0.5" } indoc = { version = "2.0.5" }
itertools = { version = "0.14.0" } itertools = { version = "0.14.0" }
jiff = { version = "0.2.0", features = ["serde"] } jiff = { version = "0.2.0", features = ["serde"] }
@ -126,7 +128,7 @@ md-5 = { version = "0.10.6" }
memchr = { version = "2.7.4" } memchr = { version = "2.7.4" }
miette = { version = "7.2.0", features = ["fancy-no-backtrace"] } miette = { version = "7.2.0", features = ["fancy-no-backtrace"] }
nanoid = { version = "0.4.0" } nanoid = { version = "0.4.0" }
nix = { version = "0.29.0", features = ["signal"] } nix = { version = "0.30.0", features = ["signal"] }
once_cell = { version = "1.20.2" } once_cell = { version = "1.20.2" }
owo-colors = { version = "4.1.0" } owo-colors = { version = "4.1.0" }
path-slash = { version = "0.2.1" } path-slash = { version = "0.2.1" }
@ -135,22 +137,23 @@ percent-encoding = { version = "2.3.1" }
petgraph = { version = "0.8.0" } petgraph = { version = "0.8.0" }
proc-macro2 = { version = "1.0.86" } proc-macro2 = { version = "1.0.86" }
procfs = { version = "0.17.0", default-features = false, features = ["flate2"] } procfs = { version = "0.17.0", default-features = false, features = ["flate2"] }
pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "73d6ecf5a4e4eb1c754b8c3255c4d31bdc266fdb" } pubgrub = { git = "https://github.com/astral-sh/pubgrub", rev = "06ec5a5f59ffaeb6cf5079c6cb184467da06c9db" }
quote = { version = "1.0.37" } quote = { version = "1.0.37" }
rayon = { version = "1.10.0" } rayon = { version = "1.10.0" }
ref-cast = { version = "1.0.24" }
reflink-copy = { version = "0.1.19" } reflink-copy = { version = "0.1.19" }
regex = { version = "1.10.6" } regex = { version = "1.10.6" }
regex-automata = { version = "0.4.8", default-features = false, features = ["dfa-build", "dfa-search", "perf", "std", "syntax"] } regex-automata = { version = "0.4.8", default-features = false, features = ["dfa-build", "dfa-search", "perf", "std", "syntax"] }
reqwest = { version = "0.12.7", default-features = false, features = ["json", "gzip", "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 = { version = "0.4.0", features = ["multipart"] } reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8", features = ["multipart"] }
reqwest-retry = { version = "0.7.0" } reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" }
rkyv = { version = "0.8.8", features = ["bytecheck"] } rkyv = { version = "0.8.8", features = ["bytecheck"] }
rmp-serde = { version = "1.3.0" } rmp-serde = { version = "1.3.0" }
rust-netrc = { version = "0.1.2" } rust-netrc = { version = "0.1.2" }
rustc-hash = { version = "2.0.0" } rustc-hash = { version = "2.0.0" }
rustix = { version = "1.0.0", default-features = false, features = ["fs", "std"] } rustix = { version = "1.0.0", default-features = false, features = ["fs", "std"] }
same-file = { version = "1.0.6" } same-file = { version = "1.0.6" }
schemars = { version = "0.8.21", features = ["url"] } schemars = { version = "1.0.0", features = ["url2"] }
seahash = { version = "4.1.0" } seahash = { version = "4.1.0" }
self-replace = { version = "1.5.0" } self-replace = { version = "1.5.0" }
serde = { version = "1.0.210", features = ["derive", "rc"] } serde = { version = "1.0.210", features = ["derive", "rc"] }
@ -170,8 +173,8 @@ tl = { git = "https://github.com/astral-sh/tl.git", rev = "6e25b2ee2513d75385101
tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync"] } tokio = { version = "1.40.0", features = ["fs", "io-util", "macros", "process", "rt", "signal", "sync"] }
tokio-stream = { version = "0.1.16" } tokio-stream = { version = "0.1.16" }
tokio-util = { version = "0.7.12", features = ["compat", "io"] } tokio-util = { version = "0.7.12", features = ["compat", "io"] }
toml = { version = "0.8.19" } toml = { version = "0.9.2", features = ["fast_hash"] }
toml_edit = { version = "0.22.21", features = ["serde"] } toml_edit = { version = "0.23.2", features = ["serde"] }
tracing = { version = "0.1.40" } tracing = { version = "0.1.40" }
tracing-durations-export = { version = "0.3.0", features = ["plot"] } tracing-durations-export = { version = "0.3.0", features = ["plot"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry"] }
@ -180,16 +183,34 @@ tracing-tree = { version = "0.4.0" }
unicode-width = { version = "0.2.0" } unicode-width = { version = "0.2.0" }
unscanny = { version = "0.1.0" } unscanny = { version = "0.1.0" }
url = { version = "2.5.2", features = ["serde"] } url = { version = "2.5.2", features = ["serde"] }
version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "73d6ecf5a4e4eb1c754b8c3255c4d31bdc266fdb" } version-ranges = { git = "https://github.com/astral-sh/pubgrub", rev = "06ec5a5f59ffaeb6cf5079c6cb184467da06c9db" }
walkdir = { version = "2.5.0" } walkdir = { version = "2.5.0" }
which = { version = "7.0.0", features = ["regex"] } which = { version = "8.0.0", features = ["regex"] }
windows = { version = "0.59.0", features = ["Win32_Globalization", "Win32_System_Console", "Win32_System_Kernel", "Win32_System_Diagnostics_Debug", "Win32_Storage_FileSystem"] }
windows-core = { version = "0.59.0" }
windows-registry = { version = "0.5.0" } windows-registry = { version = "0.5.0" }
windows-result = { version = "0.3.0" } windows-result = { version = "0.3.0" }
windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Ioctl", "Win32_System_IO", "Win32_System_Registry"] } windows-sys = { version = "0.59.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Ioctl", "Win32_System_IO", "Win32_System_Registry"] }
winsafe = { version = "0.0.23", features = ["kernel"] } wiremock = { version = "0.6.4" }
wiremock = { version = "0.6.2" }
xz2 = { version = "0.1.7" } xz2 = { version = "0.1.7" }
zip = { version = "2.2.3", default-features = false, features = ["deflate"] } zip = { version = "2.2.3", default-features = false, features = ["deflate", "zstd", "bzip2", "lzma", "xz"] }
# dev-dependencies
assert_cmd = { version = "2.0.16" }
assert_fs = { version = "1.1.2" }
byteorder = { version = "1.5.0" }
filetime = { version = "0.2.25" }
http-body-util = { version = "0.1.2" }
hyper = { version = "1.4.1", features = ["server", "http1"] }
hyper-util = { version = "0.1.8", features = ["tokio"] }
ignore = { version = "0.4.23" }
insta = { version = "1.40.0", features = ["json", "filters", "redactions"] }
predicates = { version = "3.1.2" }
similar = { version = "2.6.0" }
temp-env = { version = "0.3.6" }
test-case = { version = "3.3.1" }
test-log = { version = "0.2.16", features = ["trace"], default-features = false }
whoami = { version = "1.6.0" }
[workspace.metadata.cargo-shear] [workspace.metadata.cargo-shear]
ignored = ["flate2", "xz2"] ignored = ["flate2", "xz2"]
@ -212,6 +233,7 @@ missing_panics_doc = "allow"
module_name_repetitions = "allow" module_name_repetitions = "allow"
must_use_candidate = "allow" must_use_candidate = "allow"
similar_names = "allow" similar_names = "allow"
struct_excessive_bools = "allow"
too_many_arguments = "allow" too_many_arguments = "allow"
too_many_lines = "allow" too_many_lines = "allow"
used_underscore_binding = "allow" used_underscore_binding = "allow"
@ -294,76 +316,6 @@ codegen-units = 1
[profile.dist] [profile.dist]
inherits = "release" inherits = "release"
# Config for 'dist' [patch.crates-io]
[workspace.metadata.dist] reqwest-middleware = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" }
# The preferred dist version to use in CI (Cargo.toml SemVer syntax) reqwest-retry = { git = "https://github.com/astral-sh/reqwest-middleware", rev = "ad8b9d332d1773fde8b4cd008486de5973e0a3f8" }
cargo-dist-version = "0.28.4"
# make a package being included in our releases opt-in instead of opt-out
dist = false
# CI backends to support
ci = "github"
# The installers to generate for each app
installers = ["shell", "powershell"]
# The archive format to use for windows builds (defaults .zip)
windows-archive = ".zip"
# The archive format to use for non-windows builds (defaults .tar.xz)
unix-archive = ".tar.gz"
# Target platforms to build apps for (Rust target-triple syntax)
targets = [
"aarch64-apple-darwin",
"aarch64-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"arm-unknown-linux-musleabihf",
"armv7-unknown-linux-gnueabihf",
"armv7-unknown-linux-musleabihf",
"i686-pc-windows-msvc",
"i686-unknown-linux-gnu",
"i686-unknown-linux-musl",
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
]
# Whether to auto-include files like READMEs, LICENSEs, and CHANGELOGs (default true)
auto-includes = false
# Whether dist should create a Github Release or use an existing draft
create-release = true
# Which actions to run on pull requests
pr-run-mode = "plan"
# Whether CI should trigger releases with dispatches instead of tag pushes
dispatch-releases = true
# Which phase dist should use to create the GitHub release
github-release = "announce"
# Whether CI should include auto-generated code to build local artifacts
build-local-artifacts = false
# Local artifacts jobs to run in CI
local-artifacts-jobs = ["./build-binaries", "./build-docker"]
# Publish jobs to run in CI
publish-jobs = ["./publish-pypi"]
# Post-announce jobs to run in CI
post-announce-jobs = ["./publish-docs"]
# Custom permissions for GitHub Jobs
github-custom-job-permissions = { "build-docker" = { packages = "write", contents = "read", id-token = "write", attestations = "write" } }
# Whether to install an updater program
install-updater = false
# Path that installers should place binaries in
install-path = ["$XDG_BIN_HOME/", "$XDG_DATA_HOME/../bin", "~/.local/bin"]
[workspace.metadata.dist.github-custom-runners]
global = "depot-ubuntu-latest-4"
[workspace.metadata.dist.min-glibc-version]
# Override glibc version for specific target triplets.
aarch64-unknown-linux-gnu = "2.28"
# Override all remaining glibc versions.
"*" = "2.17"
[workspace.metadata.dist.github-action-commits]
"actions/checkout" = "11bd71901bbe5b1630ceea73d27597364c9af683" # v4
"actions/upload-artifact" = "6027e3dd177782cd8ab9af838c04fd81a07f1d47" # v4.6.2
"actions/download-artifact" = "d3f86a106a0bac45b974a628896c90dbdf5c8093" # v4.3.0
"actions/attest-build-provenance" = "c074443f1aee8d4aeeae555aebba3282517141b2" #v2.2.3

View file

@ -284,6 +284,16 @@ We are passionate about supporting contributors of all levels of experience and
you get involved in the project. See the you get involved in the project. See the
[contributing guide](https://github.com/astral-sh/uv/blob/main/CONTRIBUTING.md) to get started. [contributing guide](https://github.com/astral-sh/uv/blob/main/CONTRIBUTING.md) to get started.
## FAQ
#### How do you pronounce uv?
It's pronounced as "you - vee" ([`/juː viː/`](https://en.wikipedia.org/wiki/Help:IPA/English#Key))
#### How should I stylize uv?
Just "uv", please. See the [style guide](./STYLE.md#styling-uv) for details.
## Acknowledgements ## Acknowledgements
uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're

View file

@ -960,7 +960,7 @@ argument (or the `UV_INDEX` environment variable); to replace the default index
These changes are entirely backwards-compatible with the deprecated `--index-url` and These changes are entirely backwards-compatible with the deprecated `--index-url` and
`--extra-index-url` options, which continue to work as before. `--extra-index-url` options, which continue to work as before.
See the [Index](https://docs.astral.sh/uv/configuration/indexes/) documentation for more. See the [Index](https://docs.astral.sh/uv/concepts/indexes/) documentation for more.
### Enhancements ### Enhancements

View file

@ -1,3 +1,5 @@
# Changelog 0.6.x
## 0.6.0 ## 0.6.0
There have been 31 releases and 1135 pull requests since There have been 31 releases and 1135 pull requests since

995
changelogs/0.7.x.md Normal file
View file

@ -0,0 +1,995 @@
# Changelog 0.7.x
## 0.7.0
This release contains various changes that improve correctness and user experience, but could break
some workflows; many changes have been marked as breaking out of an abundance of caution. We expect
most users to be able to upgrade without making changes.
### Breaking changes
- **Update `uv version` to display and update project versions
([#12349](https://github.com/astral-sh/uv/pull/12349))**
Previously, `uv version` displayed uv's version. Now, `uv version` will display or update the
project's version. This interface was
[heavily requested](https://github.com/astral-sh/uv/issues/6298) and, after much consideration, we
decided that transitioning the top-level command was the best option.
Here's a brief example:
```console
$ uv init example
Initialized project `example` at `./example`
$ cd example
$ uv version
example 0.1.0
$ uv version --bump major
example 0.1.0 => 1.0.0
$ uv version --short
1.0.0
```
If used outside of a project, uv will fallback to showing its own version still:
```console
$ uv version
warning: failed to read project: No `pyproject.toml` found in current directory or any parent directory
running `uv self version` for compatibility with old `uv version` command.
this fallback will be removed soon, pass `--preview` to make this an error.
uv 0.7.0 (4433f41c9 2025-04-29)
```
As described in the warning, `--preview` can be used to error instead:
```console
$ uv version --preview
error: No `pyproject.toml` found in current directory or any parent directory
```
The previous functionality of `uv version` was moved to `uv self version`.
- **Avoid fallback to subsequent indexes on authentication failure
([#12805](https://github.com/astral-sh/uv/pull/12805))**
When using the `first-index` strategy (the default), uv will stop searching indexes for a package
once it is found on a single index. Previously, uv considered a package as "missing" from an index
during authentication failures, such as an HTTP 401 or HTTP 403 (normally, missing packages are
represented by an HTTP 404). This behavior was motivated by unusual responses from some package
indexes, but reduces the safety of uv's index strategy when authentication fails. Now, uv will
consider an authentication failure as a stop-point when searching for a package across indexes.
The `index.ignore-error-codes` option can be used to recover the existing behavior, e.g.:
```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
ignore-error-codes = [401, 403]
```
Since PyTorch's indexes always return a HTTP 403 for missing packages, uv special-cases indexes on
the `pytorch.org` domain to ignore that error code by default.
- **Require the command in `uvx <name>` to be available in the Python environment
([#11603](https://github.com/astral-sh/uv/pull/11603))**
Previously, `uvx` would attempt to execute a command even if it was not provided by a Python
package. For example, if we presume `foo` is an empty Python package which provides no command,
`uvx foo` would invoke the `foo` command on the `PATH` (if present). Now, uv will error early if
the `foo` executable is not provided by the requested Python package. This check is not enforced
when `--from` is used, so patterns like `uvx --from foo bash -c "..."` are still valid. uv also
still allows `uvx foo` where the `foo` executable is provided by a dependency of `foo` instead of
`foo` itself, as this is fairly common for packages which depend on a dedicated package for their
command-line interface.
- **Use index URL instead of package URL for keyring credential lookups
([#12651](https://github.com/astral-sh/uv/pull/12651))**
When determining credentials for querying a package URL, uv previously sent the full URL to the
`keyring` command. However, some keyring plugins expect to receive the _index URL_ (which is
usually a parent of the package URL). Now, uv requests credentials for the index URL instead. This
behavior matches `pip`.
- **Remove `--version` from subcommands ([#13108](https://github.com/astral-sh/uv/pull/13108))**
Previously, uv allowed the `--version` flag on arbitrary subcommands, e.g., `uv run --version`.
However, the `--version` flag is useful for other operations since uv is a package manager.
Consequently, we've removed the `--version` flag from subcommands — it is only available as
`uv --version`.
- **Omit Python 3.7 downloads from managed versions
([#13022](https://github.com/astral-sh/uv/pull/13022))**
Python 3.7 is EOL and not formally supported by uv; however, Python 3.7 was previously available
for download on a subset of platforms.
- **Reject non-PEP 751 TOML files in install, compile, and export commands
([#13120](https://github.com/astral-sh/uv/pull/13120),
[#13119](https://github.com/astral-sh/uv/pull/13119))**
Previously, uv treated arbitrary `.toml` files passed to commands (e.g.,
`uv pip install -r foo.toml` or `uv pip compile -o foo.toml`) as `requirements.txt`-formatted
files. Now, uv will error instead. If using PEP 751 lockfiles, use the standardized format for
custom names instead, e.g., `pylock.foo.toml`.
- **Ignore arbitrary Python requests in version files
([#12909](https://github.com/astral-sh/uv/pull/12909))**
uv allows arbitrary strings to be used for Python version requests, in which they are treated as
an executable name to search for in the `PATH`. However, using this form of request in
`.python-version` files is non-standard and conflicts with `pyenv-virtualenv` which writes
environment names to `.python-version` files. In this release, uv will now ignore requests that
are arbitrary strings when found in `.python-version` files.
- **Error on unknown dependency object specifiers
([12811](https://github.com/astral-sh/uv/pull/12811))**
The `[dependency-groups]` entries can include "object specifiers", e.g. `set-phasers-to = ...` in:
```toml
[dependency-groups]
foo = ["pyparsing"]
bar = [{set-phasers-to = "stun"}]
```
However, the only current spec-compliant object specifier is `include-group`. Previously, uv would
ignore unknown object specifiers. Now, uv will error.
- **Make `--frozen` and `--no-sources` conflicting options
([#12671](https://github.com/astral-sh/uv/pull/12671))**
Using `--no-sources` always requires a new resolution and `--frozen` will always fail when used
with it. Now, this conflict is encoded in the CLI options for clarity.
- **Treat empty `UV_PYTHON_INSTALL_DIR` and `UV_TOOL_DIR` as unset
([#12907](https://github.com/astral-sh/uv/pull/12907),
[#12905](https://github.com/astral-sh/uv/pull/12905))**
Previously, these variables were treated as set to the current working directory when set to an
empty string. Now, uv will ignore these variables when empty. This matches uv's behavior for other
environment variables which configure directories.
### Enhancements
- Disallow mixing requirements across PyTorch indexes
([#13179](https://github.com/astral-sh/uv/pull/13179))
- Add optional managed Python archive download cache
([#12175](https://github.com/astral-sh/uv/pull/12175))
- Add `poetry-core` as a `uv init` build backend option
([#12781](https://github.com/astral-sh/uv/pull/12781))
- Show tag hints when failing to find a compatible wheel in `pylock.toml`
([#13136](https://github.com/astral-sh/uv/pull/13136))
- Report Python versions in `pyvenv.cfg` version mismatch
([#13027](https://github.com/astral-sh/uv/pull/13027))
### Bug fixes
- Avoid erroring on omitted wheel-only packages in `pylock.toml`
([#13132](https://github.com/astral-sh/uv/pull/13132))
- Fix display name for `uvx --version` ([#13109](https://github.com/astral-sh/uv/pull/13109))
- Restore handling of authentication when encountering redirects
([#13050](https://github.com/astral-sh/uv/pull/13050))
- Respect build options (`--no-binary` et al) in `pylock.toml`
([#13134](https://github.com/astral-sh/uv/pull/13134))
- Use `upload-time` rather than `upload_time` in `uv.lock`
([#13176](https://github.com/astral-sh/uv/pull/13176))
### Documentation
- Changed `fish` completions append `>>` to overwrite `>`
([#13130](https://github.com/astral-sh/uv/pull/13130))
- Add `pylock.toml` mentions where relevant ([#13115](https://github.com/astral-sh/uv/pull/13115))
- Add ROCm example to the PyTorch guide ([#13200](https://github.com/astral-sh/uv/pull/13200))
- Upgrade PyTorch guide to CUDA 12.8 and PyTorch 2.7
([#13199](https://github.com/astral-sh/uv/pull/13199))
## 0.7.1
### Enhancement
- Add support for BLAKE2b-256 ([#13204](https://github.com/astral-sh/uv/pull/13204))
### Bugfix
- Revert fix handling of authentication when encountering redirects
([#13215](https://github.com/astral-sh/uv/pull/13215))
## 0.7.2
### Enhancements
- Improve trace log for retryable errors ([#13228](https://github.com/astral-sh/uv/pull/13228))
- Use "error" instead of "warning" for self-update message
([#13229](https://github.com/astral-sh/uv/pull/13229))
- Error when `uv version` is used with project-specific flags but no project is found
([#13203](https://github.com/astral-sh/uv/pull/13203))
### Bug fixes
- Fix incorrect virtual environment invalidation for pre-release Python versions
([#13234](https://github.com/astral-sh/uv/pull/13234))
- Fix patching of `clang` in managed Python sysconfig
([#13237](https://github.com/astral-sh/uv/pull/13237))
- Respect `--project` in `uv version` ([#13230](https://github.com/astral-sh/uv/pull/13230))
## 0.7.3
### Enhancements
- Add `--dry-run` support to `uv self update` ([#9829](https://github.com/astral-sh/uv/pull/9829))
- Add `--show-with` to `uv tool list` to list packages included by `--with`
([#13264](https://github.com/astral-sh/uv/pull/13264))
- De-duplicate fetched index URLs ([#13205](https://github.com/astral-sh/uv/pull/13205))
- Support more zip compression formats: bzip2, lzma, xz, zstd
([#13285](https://github.com/astral-sh/uv/pull/13285))
- Add support for downloading GraalPy ([#13172](https://github.com/astral-sh/uv/pull/13172))
- Improve error message when a virtual environment Python symlink is broken
([#12168](https://github.com/astral-sh/uv/pull/12168))
- Use `fs_err` for paths in symlinking errors ([#13303](https://github.com/astral-sh/uv/pull/13303))
- Minify and embed managed Python JSON at compile time
([#12967](https://github.com/astral-sh/uv/pull/12967))
### Preview features
- Build backend: Make preview default and add configuration docs
([#12804](https://github.com/astral-sh/uv/pull/12804))
- Build backend: Allow escaping in globs ([#13313](https://github.com/astral-sh/uv/pull/13313))
- Build backend: Make builds reproducible across operating systems
([#13171](https://github.com/astral-sh/uv/pull/13171))
### Configuration
- Add `python-downloads-json-url` option for `uv.toml` to configure custom Python installations via
JSON URL ([#12974](https://github.com/astral-sh/uv/pull/12974))
### Bug fixes
- Check nested IO errors for retries ([#13260](https://github.com/astral-sh/uv/pull/13260))
- Accept `musllinux_1_0` as a valid platform tag
([#13289](https://github.com/astral-sh/uv/pull/13289))
- Fix discovery of pre-release managed Python versions in range requests
([#13330](https://github.com/astral-sh/uv/pull/13330))
- Respect locked script preferences in `uv run --with`
([#13283](https://github.com/astral-sh/uv/pull/13283))
- Retry streaming downloads on broken pipe errors
([#13281](https://github.com/astral-sh/uv/pull/13281))
- Treat already-installed base environment packages as preferences in `uv run --with`
([#13284](https://github.com/astral-sh/uv/pull/13284))
- Avoid enumerating sources in errors for path Python requests
([#13335](https://github.com/astral-sh/uv/pull/13335))
- Avoid re-creating virtual environment with `--no-sync`
([#13287](https://github.com/astral-sh/uv/pull/13287))
### Documentation
- Remove outdated description of index strategy
([#13326](https://github.com/astral-sh/uv/pull/13326))
- Update "Viewing the version" docs ([#13241](https://github.com/astral-sh/uv/pull/13241))
## 0.7.4
### Enhancements
- Add more context to external errors ([#13351](https://github.com/astral-sh/uv/pull/13351))
- Align indentation of long arguments ([#13394](https://github.com/astral-sh/uv/pull/13394))
- Preserve order of dependencies which are sorted naively
([#13334](https://github.com/astral-sh/uv/pull/13334))
- Align progress bars by largest name length ([#13266](https://github.com/astral-sh/uv/pull/13266))
- Reinstall local packages in `uv add` ([#13462](https://github.com/astral-sh/uv/pull/13462))
- Rename `--raw-sources` to `--raw` ([#13348](https://github.com/astral-sh/uv/pull/13348))
- Show 'Downgraded' when `self update` is used to install an older version
([#13340](https://github.com/astral-sh/uv/pull/13340))
- Suggest `uv self update` if required uv version is newer
([#13305](https://github.com/astral-sh/uv/pull/13305))
- Add 3.14 beta images to uv Docker images ([#13390](https://github.com/astral-sh/uv/pull/13390))
- Add comma after "i.e." in Conda environment error
([#13423](https://github.com/astral-sh/uv/pull/13423))
- Be more precise in unpinned packages warning
([#13426](https://github.com/astral-sh/uv/pull/13426))
- Fix detection of sorted dependencies when include-group is used
([#13354](https://github.com/astral-sh/uv/pull/13354))
- Fix display of HTTP responses in trace logs for retry of errors
([#13339](https://github.com/astral-sh/uv/pull/13339))
- Log skip reasons during Python installation key interpreter match checks
([#13472](https://github.com/astral-sh/uv/pull/13472))
- Redact credentials when displaying URLs ([#13333](https://github.com/astral-sh/uv/pull/13333))
### Bug fixes
- Avoid erroring on `pylock.toml` dependency entries
([#13384](https://github.com/astral-sh/uv/pull/13384))
- Avoid panics for cannot-be-a-base URLs ([#13406](https://github.com/astral-sh/uv/pull/13406))
- Ensure cached realm credentials are applied if no password is found for index URL
([#13463](https://github.com/astral-sh/uv/pull/13463))
- Fix `.tgz` parsing to respect true extension
([#13382](https://github.com/astral-sh/uv/pull/13382))
- Fix double self-dependency ([#13366](https://github.com/astral-sh/uv/pull/13366))
- Reject `pylock.toml` in `uv add -r` ([#13421](https://github.com/astral-sh/uv/pull/13421))
- Retain dot-separated wheel tags during cache prune
([#13379](https://github.com/astral-sh/uv/pull/13379))
- Retain trailing comments after PEP 723 metadata block
([#13460](https://github.com/astral-sh/uv/pull/13460))
### Documentation
- Use "export" instead of "install" in `uv export` arguments
([#13430](https://github.com/astral-sh/uv/pull/13430))
- Remove extra newline ([#13461](https://github.com/astral-sh/uv/pull/13461))
### Preview features
- Build backend: Normalize glob paths ([#13465](https://github.com/astral-sh/uv/pull/13465))
## 0.7.5
### Bug fixes
- Support case-sensitive module discovery in the build backend
([#13468](https://github.com/astral-sh/uv/pull/13468))
- Bump Simple cache bucket to v16 ([#13498](https://github.com/astral-sh/uv/pull/13498))
- Don't error when the script is too short for the buffer
([#13488](https://github.com/astral-sh/uv/pull/13488))
- Add missing word in "script not supported" error
([#13483](https://github.com/astral-sh/uv/pull/13483))
## 0.7.6
### Python
- Add Python 3.14 on musl
- Add free-threaded Python on musl
- Add Python 3.14.0a7
- Statically link `libpython` into the interpreter on Linux for a significant performance boost
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250517)
for more details.
### Enhancements
- Improve compatibility of `VIRTUAL_ENV_PROMPT` value
([#13501](https://github.com/astral-sh/uv/pull/13501))
- Bump MSRV to 1.85 and Edition 2024 ([#13516](https://github.com/astral-sh/uv/pull/13516))
### Bug fixes
- Respect default extras in uv remove ([#13380](https://github.com/astral-sh/uv/pull/13380))
### Documentation
- Fix PowerShell code blocks ([#13511](https://github.com/astral-sh/uv/pull/13511))
## 0.7.7
### Python
- Work around third-party packages that (incorrectly) assume the interpreter is dynamically linking
libpython
- Allow the experimental JIT to be enabled at runtime on Python 3.13 and 3.14 on macOS on aarch64
aka Apple Silicon
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250521)
for more details.
### Bug fixes
- Make `uv version` lock and sync ([#13317](https://github.com/astral-sh/uv/pull/13317))
- Fix references to `ldd` in diagnostics to correctly refer to `ld.so`
([#13552](https://github.com/astral-sh/uv/pull/13552))
### Documentation
- Clarify adding SSH Git dependencies ([#13534](https://github.com/astral-sh/uv/pull/13534))
## 0.7.8
### Python
We are reverting most of our Python changes from `uv 0.7.6` and `uv 0.7.7` due to a miscompilation
that makes the Python interpreter behave incorrectly, resulting in spurious type-errors involving
str. This issue seems to be isolated to x86_64 Linux, and affected at least Python 3.12, 3.13, and
3.14.
The following changes that were introduced in those versions of uv are temporarily being reverted
while we test and deploy a proper fix for the miscompilation:
- Add Python 3.14 on musl
- free-threaded Python on musl
- Add Python 3.14.0a7
- Statically link `libpython` into the interpreter on Linux for a significant performance boost
See [the issue for details](https://github.com/astral-sh/uv/issues/13610).
### Documentation
- Remove misleading line in pin documentation ([#13611](https://github.com/astral-sh/uv/pull/13611))
## 0.7.9
### Python
The changes reverted in [0.7.8](#078) have been restored.
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250529)
for more details.
### Enhancements
- Improve obfuscation of credentials in URLs ([#13560](https://github.com/astral-sh/uv/pull/13560))
- Allow running non-default Python implementations via `uvx`
([#13583](https://github.com/astral-sh/uv/pull/13583))
- Add `uvw` as alias for `uv` without console window on Windows
([#11786](https://github.com/astral-sh/uv/pull/11786))
- Allow discovery of x86-64 managed Python builds on macOS
([#13722](https://github.com/astral-sh/uv/pull/13722))
- Differentiate between implicit vs explicit architecture requests
([#13723](https://github.com/astral-sh/uv/pull/13723))
- Implement ordering for Python architectures to prefer native installations
([#13709](https://github.com/astral-sh/uv/pull/13709))
- Only show the first match per platform (and architecture) by default in `uv python list`
([#13721](https://github.com/astral-sh/uv/pull/13721))
- Write the path of the parent environment to an `extends-environment` key in the `pyvenv.cfg` file
of an ephemeral environment ([#13598](https://github.com/astral-sh/uv/pull/13598))
- Improve the error message when libc cannot be found, e.g., when using the distroless containers
([#13549](https://github.com/astral-sh/uv/pull/13549))
### Performance
- Avoid rendering info log level ([#13642](https://github.com/astral-sh/uv/pull/13642))
- Improve performance of `uv-python` crate's manylinux submodule
([#11131](https://github.com/astral-sh/uv/pull/11131))
- Optimize `Version` display ([#13643](https://github.com/astral-sh/uv/pull/13643))
- Reduce number of reference-checks for `uv cache clean`
([#13669](https://github.com/astral-sh/uv/pull/13669))
### Bug fixes
- Avoid reinstalling dependency group members with `--all-packages`
([#13678](https://github.com/astral-sh/uv/pull/13678))
- Don't fail direct URL hash checking with dependency metadata
([#13736](https://github.com/astral-sh/uv/pull/13736))
- Exit early on `self update` if global `--offline` is set
([#13663](https://github.com/astral-sh/uv/pull/13663))
- Fix cases where the uv lock is incorrectly marked as out of date
([#13635](https://github.com/astral-sh/uv/pull/13635))
- Include pre-release versions in `uv python install --reinstall`
([#13645](https://github.com/astral-sh/uv/pull/13645))
- Set `LC_ALL=C` for git when checking git worktree
([#13637](https://github.com/astral-sh/uv/pull/13637))
- Avoid rejecting Windows paths for remote Python download JSON targets
([#13625](https://github.com/astral-sh/uv/pull/13625))
### Preview
- Add `uv add --bounds` to configure version constraints
([#12946](https://github.com/astral-sh/uv/pull/12946))
### Documentation
- Add documentation about Python versions to Tools concept page
([#7673](https://github.com/astral-sh/uv/pull/7673))
- Add example of enabling Dependabot ([#13692](https://github.com/astral-sh/uv/pull/13692))
- Fix `exclude-newer` date format for persistent configuration files
([#13706](https://github.com/astral-sh/uv/pull/13706))
- Quote versions variables in GitLab documentation
([#13679](https://github.com/astral-sh/uv/pull/13679))
- Update Dependabot support status ([#13690](https://github.com/astral-sh/uv/pull/13690))
- Explicitly specify to add a new repo entry to the repos list item in the `.pre-commit-config.yaml`
([#10243](https://github.com/astral-sh/uv/pull/10243))
- Add integration with marimo guide ([#13691](https://github.com/astral-sh/uv/pull/13691))
- Add pronunciation to README ([#5336](https://github.com/astral-sh/uv/pull/5336))
## 0.7.10
### Enhancements
- Add `--show-extras` to `uv tool list` ([#13783](https://github.com/astral-sh/uv/pull/13783))
- Add dynamically generated sysconfig replacement mappings
([#13441](https://github.com/astral-sh/uv/pull/13441))
- Add data locations to install wheel logs ([#13797](https://github.com/astral-sh/uv/pull/13797))
### Bug fixes
- Avoid redaction of placeholder `git` username when using SSH authentication
([#13799](https://github.com/astral-sh/uv/pull/13799))
- Propagate credentials to files on devpi indexes ending in `/+simple`
([#13743](https://github.com/astral-sh/uv/pull/13743))
- Restore retention of credentials for direct URLs in `uv export`
([#13809](https://github.com/astral-sh/uv/pull/13809))
## 0.7.11
### Python
- Add Python 3.14.0b1
- Add Python 3.13.4
- Add Python 3.12.11
- Add Python 3.11.13
- Add Python 3.10.18
- Add Python 3.9.23
### Enhancements
- Add Pyodide support ([#12731](https://github.com/astral-sh/uv/pull/12731))
- Better error message for version specifier with missing operator
([#13803](https://github.com/astral-sh/uv/pull/13803))
### Bug fixes
- Downgrade `reqwest` and `hyper-util` to resolve connection reset errors over IPv6
([#13835](https://github.com/astral-sh/uv/pull/13835))
- Prefer `uv`'s binary's version when checking if it's up to date
([#13840](https://github.com/astral-sh/uv/pull/13840))
### Documentation
- Use "terminal driver" instead of "shell" in `SIGINT` docs
([#13787](https://github.com/astral-sh/uv/pull/13787))
## 0.7.12
### Enhancements
- Add `uv python pin --rm` to remove `.python-version` pins
([#13860](https://github.com/astral-sh/uv/pull/13860))
- Don't hint at versions removed by `excluded-newer`
([#13884](https://github.com/astral-sh/uv/pull/13884))
- Add hint to use `tool.uv.environments` on resolution error
([#13455](https://github.com/astral-sh/uv/pull/13455))
- Add hint to use `tool.uv.required-environments` on resolution error
([#13575](https://github.com/astral-sh/uv/pull/13575))
- Improve `python pin` error messages ([#13862](https://github.com/astral-sh/uv/pull/13862))
### Bug fixes
- Lock environments during `uv sync`, `uv add` and `uv remove` to prevent race conditions
([#13869](https://github.com/astral-sh/uv/pull/13869))
- Add `--no-editable` to `uv export` for `pylock.toml`
([#13852](https://github.com/astral-sh/uv/pull/13852))
### Documentation
- List `.gitignore` in project init files ([#13855](https://github.com/astral-sh/uv/pull/13855))
- Move the pip interface documentation into the concepts section
([#13841](https://github.com/astral-sh/uv/pull/13841))
- Remove the configuration section in favor of concepts / reference
([#13842](https://github.com/astral-sh/uv/pull/13842))
- Update Git and GitHub Actions docs to mention `gh auth login`
([#13850](https://github.com/astral-sh/uv/pull/13850))
### Preview
- Fix directory glob traversal fallback preventing exclusion of all files
([#13882](https://github.com/astral-sh/uv/pull/13882))
## 0.7.13
### Python
- Add Python 3.14.0b2
- Add Python 3.13.5
- Fix stability of `uuid.getnode` on 3.13
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250612)
for more details.
### Enhancements
- Download versions in `uv python pin` if not found
([#13946](https://github.com/astral-sh/uv/pull/13946))
- Use TTY detection to determine if SIGINT forwarding is enabled
([#13925](https://github.com/astral-sh/uv/pull/13925))
- Avoid fetching an exact, cached Git commit, even if it isn't locked
([#13748](https://github.com/astral-sh/uv/pull/13748))
- Add `zstd` and `deflate` to `Accept-Encoding`
([#13982](https://github.com/astral-sh/uv/pull/13982))
- Build binaries for riscv64 ([#12688](https://github.com/astral-sh/uv/pull/12688))
### Bug fixes
- Check if relative URL is valid directory before treating as index
([#13917](https://github.com/astral-sh/uv/pull/13917))
- Ignore Python discovery errors during `uv python pin`
([#13944](https://github.com/astral-sh/uv/pull/13944))
- Do not allow `uv add --group ... --script` ([#13997](https://github.com/astral-sh/uv/pull/13997))
### Preview changes
- Build backend: Support namespace packages ([#13833](https://github.com/astral-sh/uv/pull/13833))
### Documentation
- Add 3.14 to the supported platform reference
([#13990](https://github.com/astral-sh/uv/pull/13990))
- Add an `llms.txt` to uv ([#13929](https://github.com/astral-sh/uv/pull/13929))
- Add supported macOS version to the platform reference
([#13993](https://github.com/astral-sh/uv/pull/13993))
- Update platform support reference to include Python implementation list
([#13991](https://github.com/astral-sh/uv/pull/13991))
- Update pytorch.md ([#13899](https://github.com/astral-sh/uv/pull/13899))
- Update the CLI help and reference to include references to the Python bin directory
([#13978](https://github.com/astral-sh/uv/pull/13978))
## 0.7.14
### Enhancements
- Add XPU to `--torch-backend` ([#14172](https://github.com/astral-sh/uv/pull/14172))
- Add ROCm backends to `--torch-backend` ([#14120](https://github.com/astral-sh/uv/pull/14120))
- Remove preview label from `--torch-backend` ([#14119](https://github.com/astral-sh/uv/pull/14119))
- Add `[tool.uv.dependency-groups].mygroup.requires-python`
([#13735](https://github.com/astral-sh/uv/pull/13735))
- Add auto-detection for AMD GPUs ([#14176](https://github.com/astral-sh/uv/pull/14176))
- Show retries for HTTP status code errors ([#13897](https://github.com/astral-sh/uv/pull/13897))
- Support transparent Python patch version upgrades
([#13954](https://github.com/astral-sh/uv/pull/13954))
- Warn on empty index directory ([#13940](https://github.com/astral-sh/uv/pull/13940))
- Publish to DockerHub ([#14088](https://github.com/astral-sh/uv/pull/14088))
### Performance
- Make cold resolves about 10% faster ([#14035](https://github.com/astral-sh/uv/pull/14035))
### Bug fixes
- Don't use walrus operator in interpreter query script
([#14108](https://github.com/astral-sh/uv/pull/14108))
- Fix handling of changes to `requires-python`
([#14076](https://github.com/astral-sh/uv/pull/14076))
- Fix implied `platform_machine` marker for `win_amd64` platform tag
([#14041](https://github.com/astral-sh/uv/pull/14041))
- Only update existing symlink directories on preview uninstall
([#14179](https://github.com/astral-sh/uv/pull/14179))
- Serialize Python requests for tools as canonicalized strings
([#14109](https://github.com/astral-sh/uv/pull/14109))
- Support netrc and same-origin credential propagation on index redirects
([#14126](https://github.com/astral-sh/uv/pull/14126))
- Support reading `dependency-groups` from pyproject.tomls with no `[project]`
([#13742](https://github.com/astral-sh/uv/pull/13742))
- Handle an existing shebang in `uv init --script`
([#14141](https://github.com/astral-sh/uv/pull/14141))
- Prevent concurrent updates of the environment in `uv run`
([#14153](https://github.com/astral-sh/uv/pull/14153))
- Filter managed Python distributions by platform before querying when included in request
([#13936](https://github.com/astral-sh/uv/pull/13936))
### Documentation
- Replace cuda124 with cuda128 ([#14168](https://github.com/astral-sh/uv/pull/14168))
- Document the way member sources shadow workspace sources
([#14136](https://github.com/astral-sh/uv/pull/14136))
- Sync documented PyTorch integration index for CUDA and ROCm versions from PyTorch website
([#14100](https://github.com/astral-sh/uv/pull/14100))
## 0.7.15
### Enhancements
- Consistently use `Ordering::Relaxed` for standalone atomic use cases
([#14190](https://github.com/astral-sh/uv/pull/14190))
- Warn on ambiguous relative paths for `--index`
([#14152](https://github.com/astral-sh/uv/pull/14152))
- Skip GitHub fast path when rate-limited ([#13033](https://github.com/astral-sh/uv/pull/13033))
- Preserve newlines in `schema.json` descriptions
([#13693](https://github.com/astral-sh/uv/pull/13693))
### Bug fixes
- Add check for using minor version link when creating a venv on Windows
([#14252](https://github.com/astral-sh/uv/pull/14252))
- Strip query parameters when parsing source URL
([#14224](https://github.com/astral-sh/uv/pull/14224))
### Documentation
- Add a link to PyPI FAQ to clarify what per-project token is
([#14242](https://github.com/astral-sh/uv/pull/14242))
### Preview features
- Allow symlinks in the build backend ([#14212](https://github.com/astral-sh/uv/pull/14212))
## 0.7.16
### Python
- Add Python 3.14.0b3
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250626)
for more details.
### Enhancements
- Include path or URL when failing to convert in lockfile
([#14292](https://github.com/astral-sh/uv/pull/14292))
- Warn when `~=` is used as a Python version specifier without a patch version
([#14008](https://github.com/astral-sh/uv/pull/14008))
### Preview features
- Ensure preview default Python installs are upgradeable
([#14261](https://github.com/astral-sh/uv/pull/14261))
### Performance
- Share workspace cache between lock and sync operations
([#14321](https://github.com/astral-sh/uv/pull/14321))
### Bug fixes
- Allow local indexes to reference remote files
([#14294](https://github.com/astral-sh/uv/pull/14294))
- Avoid rendering desugared prefix matches in error messages
([#14195](https://github.com/astral-sh/uv/pull/14195))
- Avoid using path URL for workspace Git dependencies in `requirements.txt`
([#14288](https://github.com/astral-sh/uv/pull/14288))
- Normalize index URLs to remove trailing slash
([#14245](https://github.com/astral-sh/uv/pull/14245))
- Respect URL-encoded credentials in redirect location
([#14315](https://github.com/astral-sh/uv/pull/14315))
- Lock the source tree when running setuptools, to protect concurrent builds
([#14174](https://github.com/astral-sh/uv/pull/14174))
### Documentation
- Note that GCP Artifact Registry download URLs must have `/simple` component
([#14251](https://github.com/astral-sh/uv/pull/14251))
## 0.7.17
### Bug fixes
- Apply build constraints when resolving `--with` dependencies
([#14340](https://github.com/astral-sh/uv/pull/14340))
- Drop trailing slashes when converting index URL from URL
([#14346](https://github.com/astral-sh/uv/pull/14346))
- Ignore `UV_PYTHON_CACHE_DIR` when empty ([#14336](https://github.com/astral-sh/uv/pull/14336))
- Fix error message ordering for `pyvenv.cfg` version conflict
([#14329](https://github.com/astral-sh/uv/pull/14329))
## 0.7.18
### Python
- Added arm64 Windows Python 3.11, 3.12, 3.13, and 3.14 These are not downloaded by default, since
x86-64 Python has broader ecosystem support on Windows. However, they can be requested with
`cpython-<version>-windows-aarch64`.
See the
[python-build-standalone release](https://github.com/astral-sh/python-build-standalone/releases/tag/20250630)
for more details.
### Enhancements
- Keep track of retries in `ManagedPythonDownload::fetch_with_retry`
([#14378](https://github.com/astral-sh/uv/pull/14378))
- Reuse build (virtual) environments across resolution and installation
([#14338](https://github.com/astral-sh/uv/pull/14338))
- Improve trace message for cached Python interpreter query
([#14328](https://github.com/astral-sh/uv/pull/14328))
- Use parsed URLs for conflicting URL error message
([#14380](https://github.com/astral-sh/uv/pull/14380))
### Preview features
- Ignore invalid build backend settings when not building
([#14372](https://github.com/astral-sh/uv/pull/14372))
### Bug fixes
- Fix equals-star and tilde-equals with `python_version` and `python_full_version`
([#14271](https://github.com/astral-sh/uv/pull/14271))
- Include the canonical path in the interpreter query cache key
([#14331](https://github.com/astral-sh/uv/pull/14331))
- Only drop build directories on program exit ([#14304](https://github.com/astral-sh/uv/pull/14304))
- Error instead of panic on conflict between global and subcommand flags
([#14368](https://github.com/astral-sh/uv/pull/14368))
- Consistently normalize trailing slashes on URLs with no path segments
([#14349](https://github.com/astral-sh/uv/pull/14349))
### Documentation
- Add instructions for publishing to JFrog's Artifactory
([#14253](https://github.com/astral-sh/uv/pull/14253))
- Edits to the build backend documentation ([#14376](https://github.com/astral-sh/uv/pull/14376))
## 0.7.19
The **[uv build backend](https://docs.astral.sh/uv/concepts/build-backend/) is now stable**, and
considered ready for production use.
The uv build backend is a great choice for pure Python projects. It has reasonable defaults, with
the goal of requiring zero configuration for most users, but provides flexible configuration to
accommodate most Python project structures. It integrates tightly with uv, to improve messaging and
user experience. It validates project metadata and structures, preventing common mistakes. And,
finally, it's very fast — `uv sync` on a new project (from `uv init`) is 10-30x faster than with
other build backends.
To use uv as a build backend in an existing project, add `uv_build` to the `[build-system]` section
in your `pyproject.toml`:
```toml
[build-system]
requires = ["uv_build>=0.7.19,<0.8.0"]
build-backend = "uv_build"
```
In a future release, it will replace `hatchling` as the default in `uv init`. As before, uv will
remain compatible with all standards-compliant build backends.
### Python
- Add PGO distributions of Python for aarch64 Linux, which are more optimized for better performance
See the
[python-build-standalone release](https://github.com/astral-sh/python-build-standalone/releases/tag/20250702)
for more details.
### Enhancements
- Ignore Python patch version for `--universal` pip compile
([#14405](https://github.com/astral-sh/uv/pull/14405))
- Update the tilde version specifier warning to include more context
([#14335](https://github.com/astral-sh/uv/pull/14335))
- Clarify behavior and hint on tool install when no executables are available
([#14423](https://github.com/astral-sh/uv/pull/14423))
### Bug fixes
- Make project and interpreter lock acquisition non-fatal
([#14404](https://github.com/astral-sh/uv/pull/14404))
- Includes `sys.prefix` in cached environment keys to avoid `--with` collisions across projects
([#14403](https://github.com/astral-sh/uv/pull/14403))
### Documentation
- Add a migration guide from pip to uv projects
([#12382](https://github.com/astral-sh/uv/pull/12382))
## 0.7.20
### Python
- Add Python 3.14.0b4
- Add zstd support to Python 3.14 on Unix (it already was available on Windows)
- Add PyPy 7.3.20 (for Python 3.11.13)
See the [PyPy](https://pypy.org/posts/2025/07/pypy-v7320-release.html) and
[`python-build-standalone`](https://github.com/astral-sh/python-build-standalone/releases/tag/20250708)
release notes for more details.
### Enhancements
- Add `--workspace` flag to `uv add` ([#14496](https://github.com/astral-sh/uv/pull/14496))
- Add auto-detection for Intel GPUs ([#14386](https://github.com/astral-sh/uv/pull/14386))
- Drop trailing arguments when writing shebangs
([#14519](https://github.com/astral-sh/uv/pull/14519))
- Add debug message when skipping Python downloads
([#14509](https://github.com/astral-sh/uv/pull/14509))
- Add support for declaring multiple modules in namespace packages
([#14460](https://github.com/astral-sh/uv/pull/14460))
### Bug fixes
- Revert normalization of trailing slashes on index URLs
([#14511](https://github.com/astral-sh/uv/pull/14511))
- Fix forced resolution with all extras in `uv version`
([#14434](https://github.com/astral-sh/uv/pull/14434))
- Fix handling of pre-releases in preferences ([#14498](https://github.com/astral-sh/uv/pull/14498))
- Remove transparent variants in `uv-extract` to enable retries
([#14450](https://github.com/astral-sh/uv/pull/14450))
### Rust API
- Add method to get packages involved in a `NoSolutionError`
([#14457](https://github.com/astral-sh/uv/pull/14457))
- Make `ErrorTree` for `NoSolutionError` public
([#14444](https://github.com/astral-sh/uv/pull/14444))
### Documentation
- Finish incomplete sentence in pip migration guide
([#14432](https://github.com/astral-sh/uv/pull/14432))
- Remove `cache-dependency-glob` examples for `setup-uv`
([#14493](https://github.com/astral-sh/uv/pull/14493))
- Remove `uv pip sync` suggestion with `pyproject.toml`
([#14510](https://github.com/astral-sh/uv/pull/14510))
- Update documentation for GitHub to use `setup-uv@v6`
([#14490](https://github.com/astral-sh/uv/pull/14490))
## 0.7.21
### Python
- Restore the SQLite `fts4`, `fts5`, `rtree`, and `geopoly` extensions on macOS and Linux
See the
[`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250712)
for more details.
### Enhancements
- Add `--python-platform` to `uv sync` ([#14320](https://github.com/astral-sh/uv/pull/14320))
- Support pre-releases in `uv version --bump` ([#13578](https://github.com/astral-sh/uv/pull/13578))
- Add `-w` shorthand for `--with` ([#14530](https://github.com/astral-sh/uv/pull/14530))
- Add an exception handler on Windows to display information on crash
([#14582](https://github.com/astral-sh/uv/pull/14582))
- Add hint when Python downloads are disabled ([#14522](https://github.com/astral-sh/uv/pull/14522))
- Add `UV_HTTP_RETRIES` to customize retry counts
([#14544](https://github.com/astral-sh/uv/pull/14544))
- Follow leaf symlinks matched by globs in `cache-key`
([#13438](https://github.com/astral-sh/uv/pull/13438))
- Support parent path components (`..`) in globs in `cache-key`
([#13469](https://github.com/astral-sh/uv/pull/13469))
- Improve `cache-key` performance ([#13469](https://github.com/astral-sh/uv/pull/13469))
### Preview features
- Add `uv sync --output-format json` ([#13689](https://github.com/astral-sh/uv/pull/13689))
### Bug fixes
- Do not re-resolve with a new Python version in `uv tool` if it is incompatible with `--python`
([#14606](https://github.com/astral-sh/uv/pull/14606))
### Documentation
- Document how to nest dependency groups with `include-group`
([#14539](https://github.com/astral-sh/uv/pull/14539))
- Fix repeated word in Pyodide doc ([#14554](https://github.com/astral-sh/uv/pull/14554))
- Update CONTRIBUTING.md with instructions to format Markdown files via Docker
([#14246](https://github.com/astral-sh/uv/pull/14246))
- Fix version number for `setup-python` ([#14533](https://github.com/astral-sh/uv/pull/14533))
## 0.7.22
### Python
- Upgrade GraalPy to 24.2.2
See the [GraalPy release notes](https://github.com/oracle/graalpython/releases/tag/graal-24.2.2) for
more details.
### Configuration
- Add `UV_COMPILE_BYTECODE_TIMEOUT` environment variable
([#14369](https://github.com/astral-sh/uv/pull/14369))
- Allow users to override index `cache-control` headers
([#14620](https://github.com/astral-sh/uv/pull/14620))
- Add `UV_LIBC` to override libc selection in multi-libc environment
([#14646](https://github.com/astral-sh/uv/pull/14646))
### Bug fixes
- Fix `--all-arches` when paired with `--only-downloads`
([#14629](https://github.com/astral-sh/uv/pull/14629))
- Skip Windows Python interpreters that return a broken MSIX package code
([#14636](https://github.com/astral-sh/uv/pull/14636))
- Warn on invalid `uv.toml` when provided via direct path
([#14653](https://github.com/astral-sh/uv/pull/14653))
- Improve async signal safety in Windows exception handler
([#14619](https://github.com/astral-sh/uv/pull/14619))
### Documentation
- Mention the `revision` in the lockfile versioning doc
([#14634](https://github.com/astral-sh/uv/pull/14634))
- Move "Conflicting dependencies" to the "Resolution" page
([#14633](https://github.com/astral-sh/uv/pull/14633))
- Rename "Dependency specifiers" section to exclude PEP 508 reference
([#14631](https://github.com/astral-sh/uv/pull/14631))
- Suggest `uv cache clean` prior to `--reinstall`
([#14659](https://github.com/astral-sh/uv/pull/14659))
### Preview features
- Make preview Python registration on Windows non-fatal
([#14614](https://github.com/astral-sh/uv/pull/14614))
- Update preview installation of Python executables to be non-fatal
([#14612](https://github.com/astral-sh/uv/pull/14612))
- Add `uv python update-shell` ([#14627](https://github.com/astral-sh/uv/pull/14627))

View file

@ -6,6 +6,8 @@ doc-valid-idents = [
"GraalPy", "GraalPy",
"ReFS", "ReFS",
"PyTorch", "PyTorch",
"ROCm",
"XPU",
".." # Include the defaults ".." # Include the defaults
] ]
@ -35,7 +37,7 @@ disallowed-methods = [
"std::fs::soft_link", "std::fs::soft_link",
"std::fs::symlink_metadata", "std::fs::symlink_metadata",
"std::fs::write", "std::fs::write",
"std::os::unix::fs::symlink", { path = "std::os::unix::fs::symlink", allow-invalid = true },
"std::os::windows::fs::symlink_dir", { path = "std::os::windows::fs::symlink_dir", allow-invalid = true },
"std::os::windows::fs::symlink_file", { path = "std::os::windows::fs::symlink_file", allow-invalid = true },
] ]

View file

@ -11,6 +11,7 @@ workspace = true
[dependencies] [dependencies]
uv-once-map = { workspace = true } uv-once-map = { workspace = true }
uv-redacted = { workspace = true }
uv-small-str = { workspace = true } uv-small-str = { workspace = true }
uv-static = { workspace = true } uv-static = { workspace = true }
uv-warnings = { workspace = true } uv-warnings = { workspace = true }
@ -32,9 +33,8 @@ tracing = { workspace = true }
url = { workspace = true } url = { workspace = true }
[dev-dependencies] [dev-dependencies]
insta = { version = "1.40.0" } insta = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }
test-log = { version = "0.2.16", features = ["trace"], default-features = false } test-log = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
tracing-test = { workspace = true }
wiremock = { workspace = true } wiremock = { workspace = true }

View file

@ -9,6 +9,7 @@ use tracing::trace;
use url::Url; use url::Url;
use uv_once_map::OnceMap; use uv_once_map::OnceMap;
use uv_redacted::DisplaySafeUrl;
use crate::Realm; use crate::Realm;
use crate::credentials::{Credentials, Username}; use crate::credentials::{Credentials, Username};
@ -18,7 +19,7 @@ type FxOnceMap<K, V> = OnceMap<K, V, BuildHasherDefault<FxHasher>>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(crate) enum FetchUrl { pub(crate) enum FetchUrl {
/// A full index URL /// A full index URL
Index(Url), Index(DisplaySafeUrl),
/// A realm URL /// A realm URL
Realm(Realm), Realm(Realm),
} }

View file

@ -3,6 +3,7 @@ use base64::read::DecoderReader;
use base64::write::EncoderWriter; use base64::write::EncoderWriter;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use uv_redacted::DisplaySafeUrl;
use netrc::Netrc; use netrc::Netrc;
use reqwest::Request; use reqwest::Request;
@ -141,7 +142,11 @@ impl Credentials {
/// Return [`Credentials`] for a [`Url`] from a [`Netrc`] file, if any. /// Return [`Credentials`] for a [`Url`] from a [`Netrc`] file, if any.
/// ///
/// If a username is provided, it must match the login in the netrc file or [`None`] is returned. /// If a username is provided, it must match the login in the netrc file or [`None`] is returned.
pub(crate) fn from_netrc(netrc: &Netrc, url: &Url, username: Option<&str>) -> Option<Self> { pub(crate) fn from_netrc(
netrc: &Netrc,
url: &DisplaySafeUrl,
username: Option<&str>,
) -> Option<Self> {
let host = url.host_str()?; let host = url.host_str()?;
let entry = netrc let entry = netrc
.hosts .hosts
@ -299,7 +304,7 @@ impl Credentials {
/// ///
/// Any existing credentials will be overridden. /// Any existing credentials will be overridden.
#[must_use] #[must_use]
pub fn apply(&self, mut url: Url) -> Url { pub fn apply(&self, mut url: DisplaySafeUrl) -> DisplaySafeUrl {
if let Some(username) = self.username() { if let Some(username) = self.username() {
let _ = url.set_username(username); let _ = url.set_username(username);
} }

View file

@ -2,6 +2,7 @@ use std::fmt::{self, Display, Formatter};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use url::Url; use url::Url;
use uv_redacted::DisplaySafeUrl;
/// When to use authentication. /// When to use authentication.
#[derive( #[derive(
@ -53,10 +54,10 @@ impl Display for AuthPolicy {
// could potentially make sense for a future refactor. // could potentially make sense for a future refactor.
#[derive(Debug, Clone, Hash, Eq, PartialEq)] #[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct Index { pub struct Index {
pub url: Url, pub url: DisplaySafeUrl,
/// The root endpoint where authentication is applied. /// The root endpoint where authentication is applied.
/// For PEP 503 endpoints, this excludes `/simple`. /// For PEP 503 endpoints, this excludes `/simple`.
pub root_url: Url, pub root_url: DisplaySafeUrl,
pub auth_policy: AuthPolicy, pub auth_policy: AuthPolicy,
} }
@ -85,7 +86,7 @@ impl Indexes {
Self(FxHashSet::default()) Self(FxHashSet::default())
} }
/// Create a new [`AuthIndexUrls`] from an iterator of [`AuthIndexUrl`]s. /// Create a new [`Indexes`] instance from an iterator of [`Index`]s.
pub fn from_indexes(urls: impl IntoIterator<Item = Index>) -> Self { pub fn from_indexes(urls: impl IntoIterator<Item = Index>) -> Self {
let mut index_urls = Self::new(); let mut index_urls = Self::new();
for url in urls { for url in urls {
@ -95,7 +96,7 @@ impl Indexes {
} }
/// Get the index URL prefix for a URL if one exists. /// Get the index URL prefix for a URL if one exists.
pub fn index_url_for(&self, url: &Url) -> Option<&Url> { pub fn index_url_for(&self, url: &Url) -> Option<&DisplaySafeUrl> {
self.find_prefix_index(url).map(|index| &index.url) self.find_prefix_index(url).map(|index| &index.url)
} }

View file

@ -1,7 +1,7 @@
use std::{io::Write, process::Stdio}; use std::{io::Write, process::Stdio};
use tokio::process::Command; use tokio::process::Command;
use tracing::{instrument, trace, warn}; use tracing::{instrument, trace, warn};
use url::Url; use uv_redacted::DisplaySafeUrl;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use crate::credentials::Credentials; use crate::credentials::Credentials;
@ -36,7 +36,7 @@ impl KeyringProvider {
/// Returns [`None`] if no password was found for the username or if any errors /// Returns [`None`] if no password was found for the username or if any errors
/// are encountered in the keyring backend. /// are encountered in the keyring backend.
#[instrument(skip_all, fields(url = % url.to_string(), username))] #[instrument(skip_all, fields(url = % url.to_string(), username))]
pub async fn fetch(&self, url: &Url, username: Option<&str>) -> Option<Credentials> { pub async fn fetch(&self, url: &DisplaySafeUrl, username: Option<&str>) -> Option<Credentials> {
// Validate the request // Validate the request
debug_assert!( debug_assert!(
url.host_str().is_some(), url.host_str().is_some(),
@ -217,13 +217,16 @@ impl KeyringProvider {
mod tests { mod tests {
use super::*; use super::*;
use futures::FutureExt; use futures::FutureExt;
use url::Url;
#[tokio::test] #[tokio::test]
async fn fetch_url_no_host() { async fn fetch_url_no_host() {
let url = Url::parse("file:/etc/bin/").unwrap(); let url = Url::parse("file:/etc/bin/").unwrap();
let keyring = KeyringProvider::empty(); let keyring = KeyringProvider::empty();
// Panics due to debug assertion; returns `None` in production // Panics due to debug assertion; returns `None` in production
let result = std::panic::AssertUnwindSafe(keyring.fetch(&url, Some("user"))) let result = std::panic::AssertUnwindSafe(
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some("user")),
)
.catch_unwind() .catch_unwind()
.await; .await;
assert!(result.is_err()); assert!(result.is_err());
@ -234,7 +237,9 @@ mod tests {
let url = Url::parse("https://user:password@example.com").unwrap(); let url = Url::parse("https://user:password@example.com").unwrap();
let keyring = KeyringProvider::empty(); let keyring = KeyringProvider::empty();
// Panics due to debug assertion; returns `None` in production // Panics due to debug assertion; returns `None` in production
let result = std::panic::AssertUnwindSafe(keyring.fetch(&url, Some(url.username()))) let result = std::panic::AssertUnwindSafe(
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some(url.username())),
)
.catch_unwind() .catch_unwind()
.await; .await;
assert!(result.is_err()); assert!(result.is_err());
@ -245,7 +250,9 @@ mod tests {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::empty(); let keyring = KeyringProvider::empty();
// Panics due to debug assertion; returns `None` in production // Panics due to debug assertion; returns `None` in production
let result = std::panic::AssertUnwindSafe(keyring.fetch(&url, Some(url.username()))) let result = std::panic::AssertUnwindSafe(
keyring.fetch(DisplaySafeUrl::ref_cast(&url), Some(url.username())),
)
.catch_unwind() .catch_unwind()
.await; .await;
assert!(result.is_err()); assert!(result.is_err());
@ -254,8 +261,9 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn fetch_url_no_auth() { async fn fetch_url_no_auth() {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let url = DisplaySafeUrl::ref_cast(&url);
let keyring = KeyringProvider::empty(); let keyring = KeyringProvider::empty();
let credentials = keyring.fetch(&url, Some("user")); let credentials = keyring.fetch(url, Some("user"));
assert!(credentials.await.is_none()); assert!(credentials.await.is_none());
} }
@ -264,7 +272,9 @@ mod tests {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
assert_eq!( assert_eq!(
keyring.fetch(&url, Some("user")).await, keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
.await,
Some(Credentials::basic( Some(Credentials::basic(
Some("user".to_string()), Some("user".to_string()),
Some("password".to_string()) Some("password".to_string())
@ -272,7 +282,10 @@ mod tests {
); );
assert_eq!( assert_eq!(
keyring keyring
.fetch(&url.join("test").unwrap(), Some("user")) .fetch(
DisplaySafeUrl::ref_cast(&url.join("test").unwrap()),
Some("user")
)
.await, .await,
Some(Credentials::basic( Some(Credentials::basic(
Some("user".to_string()), Some("user".to_string()),
@ -285,7 +298,9 @@ mod tests {
async fn fetch_url_no_match() { async fn fetch_url_no_match() {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::dummy([("other.com", "user", "password")]); let keyring = KeyringProvider::dummy([("other.com", "user", "password")]);
let credentials = keyring.fetch(&url, Some("user")).await; let credentials = keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
.await;
assert_eq!(credentials, None); assert_eq!(credentials, None);
} }
@ -297,21 +312,33 @@ mod tests {
(url.host_str().unwrap(), "user", "other-password"), (url.host_str().unwrap(), "user", "other-password"),
]); ]);
assert_eq!( assert_eq!(
keyring.fetch(&url.join("foo").unwrap(), Some("user")).await, keyring
.fetch(
DisplaySafeUrl::ref_cast(&url.join("foo").unwrap()),
Some("user")
)
.await,
Some(Credentials::basic( Some(Credentials::basic(
Some("user".to_string()), Some("user".to_string()),
Some("password".to_string()) Some("password".to_string())
)) ))
); );
assert_eq!( assert_eq!(
keyring.fetch(&url, Some("user")).await, keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
.await,
Some(Credentials::basic( Some(Credentials::basic(
Some("user".to_string()), Some("user".to_string()),
Some("other-password".to_string()) Some("other-password".to_string())
)) ))
); );
assert_eq!( assert_eq!(
keyring.fetch(&url.join("bar").unwrap(), Some("user")).await, keyring
.fetch(
DisplaySafeUrl::ref_cast(&url.join("bar").unwrap()),
Some("user")
)
.await,
Some(Credentials::basic( Some(Credentials::basic(
Some("user".to_string()), Some("user".to_string()),
Some("other-password".to_string()) Some("other-password".to_string())
@ -323,7 +350,9 @@ mod tests {
async fn fetch_url_username() { async fn fetch_url_username() {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
let credentials = keyring.fetch(&url, Some("user")).await; let credentials = keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("user"))
.await;
assert_eq!( assert_eq!(
credentials, credentials,
Some(Credentials::basic( Some(Credentials::basic(
@ -337,7 +366,7 @@ mod tests {
async fn fetch_url_no_username() { async fn fetch_url_no_username() {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]);
let credentials = keyring.fetch(&url, None).await; let credentials = keyring.fetch(DisplaySafeUrl::ref_cast(&url), None).await;
assert_eq!( assert_eq!(
credentials, credentials,
Some(Credentials::basic( Some(Credentials::basic(
@ -351,12 +380,16 @@ mod tests {
async fn fetch_url_username_no_match() { async fn fetch_url_username_no_match() {
let url = Url::parse("https://example.com").unwrap(); let url = Url::parse("https://example.com").unwrap();
let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "foo", "password")]); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "foo", "password")]);
let credentials = keyring.fetch(&url, Some("bar")).await; let credentials = keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("bar"))
.await;
assert_eq!(credentials, None); assert_eq!(credentials, None);
// Still fails if we have `foo` in the URL itself // Still fails if we have `foo` in the URL itself
let url = Url::parse("https://foo@example.com").unwrap(); let url = Url::parse("https://foo@example.com").unwrap();
let credentials = keyring.fetch(&url, Some("bar")).await; let credentials = keyring
.fetch(DisplaySafeUrl::ref_cast(&url), Some("bar"))
.await;
assert_eq!(credentials, None); assert_eq!(credentials, None);
} }
} }

View file

@ -1,7 +1,6 @@
use std::sync::{Arc, LazyLock}; use std::sync::{Arc, LazyLock};
use tracing::trace; use tracing::trace;
use url::Url;
use cache::CredentialsCache; use cache::CredentialsCache;
pub use credentials::Credentials; pub use credentials::Credentials;
@ -9,12 +8,14 @@ pub use index::{AuthPolicy, Index, Indexes};
pub use keyring::KeyringProvider; pub use keyring::KeyringProvider;
pub use middleware::AuthMiddleware; pub use middleware::AuthMiddleware;
use realm::Realm; use realm::Realm;
use uv_redacted::DisplaySafeUrl;
mod cache; mod cache;
mod credentials; mod credentials;
mod index; mod index;
mod keyring; mod keyring;
mod middleware; mod middleware;
mod providers;
mod realm; mod realm;
// TODO(zanieb): Consider passing a cache explicitly throughout // TODO(zanieb): Consider passing a cache explicitly throughout
@ -28,7 +29,7 @@ pub(crate) static CREDENTIALS_CACHE: LazyLock<CredentialsCache> =
/// Populate the global authentication store with credentials on a URL, if there are any. /// Populate the global authentication store with credentials on a URL, if there are any.
/// ///
/// Returns `true` if the store was updated. /// Returns `true` if the store was updated.
pub fn store_credentials_from_url(url: &Url) -> bool { pub fn store_credentials_from_url(url: &DisplaySafeUrl) -> bool {
if let Some(credentials) = Credentials::from_url(url) { if let Some(credentials) = Credentials::from_url(url) {
trace!("Caching credentials for {url}"); trace!("Caching credentials for {url}");
CREDENTIALS_CACHE.insert(url, Arc::new(credentials)); CREDENTIALS_CACHE.insert(url, Arc::new(credentials));
@ -41,7 +42,7 @@ pub fn store_credentials_from_url(url: &Url) -> bool {
/// Populate the global authentication store with credentials on a URL, if there are any. /// Populate the global authentication store with credentials on a URL, if there are any.
/// ///
/// Returns `true` if the store was updated. /// Returns `true` if the store was updated.
pub fn store_credentials(url: &Url, credentials: Arc<Credentials>) { pub fn store_credentials(url: &DisplaySafeUrl, credentials: Arc<Credentials>) {
trace!("Caching credentials for {url}"); trace!("Caching credentials for {url}");
CREDENTIALS_CACHE.insert(url, credentials); CREDENTIALS_CACHE.insert(url, credentials);
} }

View file

@ -1,8 +1,13 @@
use std::sync::{Arc, LazyLock}; use std::sync::{Arc, LazyLock};
use anyhow::{anyhow, format_err};
use http::{Extensions, StatusCode}; use http::{Extensions, StatusCode};
use url::Url; use netrc::Netrc;
use reqwest::{Request, Response};
use reqwest_middleware::{Error, Middleware, Next};
use tracing::{debug, trace, warn};
use crate::providers::HuggingFaceProvider;
use crate::{ use crate::{
CREDENTIALS_CACHE, CredentialsCache, KeyringProvider, CREDENTIALS_CACHE, CredentialsCache, KeyringProvider,
cache::FetchUrl, cache::FetchUrl,
@ -10,11 +15,7 @@ use crate::{
index::{AuthPolicy, Indexes}, index::{AuthPolicy, Indexes},
realm::Realm, realm::Realm,
}; };
use anyhow::{anyhow, format_err}; use uv_redacted::DisplaySafeUrl;
use netrc::Netrc;
use reqwest::{Request, Response};
use reqwest_middleware::{Error, Middleware, Next};
use tracing::{debug, trace, warn};
/// Strategy for loading netrc files. /// Strategy for loading netrc files.
enum NetrcMode { enum NetrcMode {
@ -274,6 +275,7 @@ impl Middleware for AuthMiddleware {
trace!("Checking for credentials for {url}"); trace!("Checking for credentials for {url}");
(request, None) (request, None)
}; };
let retry_request_url = DisplaySafeUrl::ref_cast(retry_request.url());
let username = credentials let username = credentials
.as_ref() .as_ref()
@ -282,13 +284,13 @@ impl Middleware for AuthMiddleware {
let credentials = if let Some(index_url) = maybe_index_url { let credentials = if let Some(index_url) = maybe_index_url {
self.cache().get_url(index_url, &username).or_else(|| { self.cache().get_url(index_url, &username).or_else(|| {
self.cache() self.cache()
.get_realm(Realm::from(retry_request.url()), username) .get_realm(Realm::from(&**retry_request_url), username)
}) })
} else { } else {
// Since there is no known index for this URL, check if there are credentials in // Since there is no known index for this URL, check if there are credentials in
// the realm-level cache. // the realm-level cache.
self.cache() self.cache()
.get_realm(Realm::from(retry_request.url()), username) .get_realm(Realm::from(&**retry_request_url), username)
} }
.or(credentials); .or(credentials);
@ -307,7 +309,7 @@ impl Middleware for AuthMiddleware {
if let Some(credentials) = self if let Some(credentials) = self
.fetch_credentials( .fetch_credentials(
credentials.as_deref(), credentials.as_deref(),
retry_request.url(), retry_request_url,
maybe_index_url, maybe_index_url,
auth_policy, auth_policy,
) )
@ -362,7 +364,7 @@ impl AuthMiddleware {
// Nothing to insert into the cache if we don't have credentials // Nothing to insert into the cache if we don't have credentials
return next.run(request, extensions).await; return next.run(request, extensions).await;
}; };
let url = request.url().clone(); let url = DisplaySafeUrl::from(request.url().clone());
if matches!(auth_policy, AuthPolicy::Always) && credentials.password().is_none() { if matches!(auth_policy, AuthPolicy::Always) && credentials.password().is_none() {
return Err(Error::Middleware(format_err!("Missing password for {url}"))); return Err(Error::Middleware(format_err!("Missing password for {url}")));
} }
@ -387,8 +389,8 @@ impl AuthMiddleware {
mut request: Request, mut request: Request,
extensions: &mut Extensions, extensions: &mut Extensions,
next: Next<'_>, next: Next<'_>,
url: &str, url: &DisplaySafeUrl,
index_url: Option<&Url>, index_url: Option<&DisplaySafeUrl>,
auth_policy: AuthPolicy, auth_policy: AuthPolicy,
) -> reqwest_middleware::Result<Response> { ) -> reqwest_middleware::Result<Response> {
let credentials = Arc::new(credentials); let credentials = Arc::new(credentials);
@ -430,7 +432,12 @@ impl AuthMiddleware {
// Do not insert already-cached credentials // Do not insert already-cached credentials
None None
} else if let Some(credentials) = self } else if let Some(credentials) = self
.fetch_credentials(Some(&credentials), request.url(), index_url, auth_policy) .fetch_credentials(
Some(&credentials),
DisplaySafeUrl::ref_cast(request.url()),
index_url,
auth_policy,
)
.await .await
{ {
request = credentials.authenticate(request); request = credentials.authenticate(request);
@ -451,9 +458,8 @@ impl AuthMiddleware {
Some(credentials) Some(credentials)
}; };
return self self.complete_request(credentials, request, extensions, next, auth_policy)
.complete_request(credentials, request, extensions, next, auth_policy) .await
.await;
} }
/// Fetch credentials for a URL. /// Fetch credentials for a URL.
@ -462,8 +468,8 @@ impl AuthMiddleware {
async fn fetch_credentials( async fn fetch_credentials(
&self, &self,
credentials: Option<&Credentials>, credentials: Option<&Credentials>,
url: &Url, url: &DisplaySafeUrl,
maybe_index_url: Option<&Url>, maybe_index_url: Option<&DisplaySafeUrl>,
auth_policy: AuthPolicy, auth_policy: AuthPolicy,
) -> Option<Arc<Credentials>> { ) -> Option<Arc<Credentials>> {
let username = Username::from( let username = Username::from(
@ -475,7 +481,7 @@ impl AuthMiddleware {
let key = if let Some(index_url) = maybe_index_url { let key = if let Some(index_url) = maybe_index_url {
(FetchUrl::Index(index_url.clone()), username) (FetchUrl::Index(index_url.clone()), username)
} else { } else {
(FetchUrl::Realm(Realm::from(url)), username) (FetchUrl::Realm(Realm::from(&**url)), username)
}; };
if !self.cache().fetches.register(key.clone()) { if !self.cache().fetches.register(key.clone()) {
let credentials = self let credentials = self
@ -497,6 +503,13 @@ impl AuthMiddleware {
return credentials; return credentials;
} }
// Support for known providers, like Hugging Face.
if let Some(credentials) = HuggingFaceProvider::credentials_for(url).map(Arc::new) {
debug!("Found Hugging Face credentials for {url}");
self.cache().fetches.done(key, Some(credentials.clone()));
return Some(credentials);
}
// Netrc support based on: <https://github.com/gribouille/netrc>. // Netrc support based on: <https://github.com/gribouille/netrc>.
let credentials = if let Some(credentials) = self.netrc.get().and_then(|netrc| { let credentials = if let Some(credentials) = self.netrc.get().and_then(|netrc| {
debug!("Checking netrc for credentials for {url}"); debug!("Checking netrc for credentials for {url}");
@ -523,7 +536,7 @@ impl AuthMiddleware {
if let Some(username) = credentials.and_then(|credentials| credentials.username()) { if let Some(username) = credentials.and_then(|credentials| credentials.username()) {
if let Some(index_url) = maybe_index_url { if let Some(index_url) = maybe_index_url {
debug!("Checking keyring for credentials for index URL {}@{}", username, index_url); debug!("Checking keyring for credentials for index URL {}@{}", username, index_url);
keyring.fetch(index_url, Some(username)).await keyring.fetch(DisplaySafeUrl::ref_cast(index_url), Some(username)).await
} else { } else {
debug!("Checking keyring for credentials for full URL {}@{}", username, url); debug!("Checking keyring for credentials for full URL {}@{}", username, url);
keyring.fetch(url, Some(username)).await keyring.fetch(url, Some(username)).await
@ -533,7 +546,7 @@ impl AuthMiddleware {
debug!( debug!(
"Checking keyring for credentials for index URL {index_url} without username due to `authenticate = always`" "Checking keyring for credentials for index URL {index_url} without username due to `authenticate = always`"
); );
keyring.fetch(index_url, None).await keyring.fetch(DisplaySafeUrl::ref_cast(index_url), None).await
} else { } else {
None None
} }
@ -558,24 +571,17 @@ impl AuthMiddleware {
} }
} }
fn tracing_url(request: &Request, credentials: Option<&Credentials>) -> String { fn tracing_url(request: &Request, credentials: Option<&Credentials>) -> DisplaySafeUrl {
if !tracing::enabled!(tracing::Level::DEBUG) { let mut url = DisplaySafeUrl::from(request.url().clone());
return request.url().to_string();
}
let mut url = request.url().clone();
if let Some(creds) = credentials { if let Some(creds) = credentials {
if creds.password().is_some() {
if let Some(username) = creds.username() { if let Some(username) = creds.username() {
let _ = url.set_username(username); let _ = url.set_username(username);
} }
let _ = url.set_password(Some("****")); if let Some(password) = creds.password() {
// A username on its own might be a secret token. let _ = url.set_password(Some(password));
} else if creds.username().is_some() {
let _ = url.set_username("****");
} }
} }
url.to_string() url
} }
#[cfg(test)] #[cfg(test)]
@ -1749,13 +1755,13 @@ mod tests {
let base_url_2 = base_url.join("prefix_2")?; let base_url_2 = base_url.join("prefix_2")?;
let indexes = Indexes::from_indexes(vec![ let indexes = Indexes::from_indexes(vec![
Index { Index {
url: base_url_1.clone(), url: DisplaySafeUrl::from(base_url_1.clone()),
root_url: base_url_1.clone(), root_url: DisplaySafeUrl::from(base_url_1.clone()),
auth_policy: AuthPolicy::Auto, auth_policy: AuthPolicy::Auto,
}, },
Index { Index {
url: base_url_2.clone(), url: DisplaySafeUrl::from(base_url_2.clone()),
root_url: base_url_2.clone(), root_url: DisplaySafeUrl::from(base_url_2.clone()),
auth_policy: AuthPolicy::Auto, auth_policy: AuthPolicy::Auto,
}, },
]); ]);
@ -1857,8 +1863,8 @@ mod tests {
let base_url = Url::parse(&server.uri())?; let base_url = Url::parse(&server.uri())?;
let index_url = base_url.join("prefix_1")?; let index_url = base_url.join("prefix_1")?;
let indexes = Indexes::from_indexes(vec![Index { let indexes = Indexes::from_indexes(vec![Index {
url: index_url.clone(), url: DisplaySafeUrl::from(index_url.clone()),
root_url: index_url.clone(), root_url: DisplaySafeUrl::from(index_url.clone()),
auth_policy: AuthPolicy::Auto, auth_policy: AuthPolicy::Auto,
}]); }]);
@ -1912,7 +1918,7 @@ mod tests {
} }
fn indexes_for(url: &Url, policy: AuthPolicy) -> Indexes { fn indexes_for(url: &Url, policy: AuthPolicy) -> Indexes {
let mut url = url.clone(); let mut url = DisplaySafeUrl::from(url.clone());
url.set_password(None).ok(); url.set_password(None).ok();
url.set_username("").ok(); url.set_username("").ok();
Indexes::from_indexes(vec![Index { Indexes::from_indexes(vec![Index {
@ -2104,16 +2110,14 @@ mod tests {
} }
#[test] #[test]
#[tracing_test::traced_test(level = "debug")]
fn test_tracing_url() { fn test_tracing_url() {
// No credentials // No credentials
let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple"); let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple");
assert_eq!( assert_eq!(
tracing_url(&req, None), tracing_url(&req, None),
"https://pypi-proxy.fly.dev/basic-auth/simple" DisplaySafeUrl::parse("https://pypi-proxy.fly.dev/basic-auth/simple").unwrap()
); );
// Mask username if there is a username but no password
let creds = Credentials::Basic { let creds = Credentials::Basic {
username: Username::new(Some(String::from("user"))), username: Username::new(Some(String::from("user"))),
password: None, password: None,
@ -2121,10 +2125,9 @@ mod tests {
let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple"); let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple");
assert_eq!( assert_eq!(
tracing_url(&req, Some(&creds)), tracing_url(&req, Some(&creds)),
"https://****@pypi-proxy.fly.dev/basic-auth/simple" DisplaySafeUrl::parse("https://user@pypi-proxy.fly.dev/basic-auth/simple").unwrap()
); );
// Log username but mask password if a password is present
let creds = Credentials::Basic { let creds = Credentials::Basic {
username: Username::new(Some(String::from("user"))), username: Username::new(Some(String::from("user"))),
password: Some(Password::new(String::from("password"))), password: Some(Password::new(String::from("password"))),
@ -2132,7 +2135,8 @@ mod tests {
let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple"); let req = create_request("https://pypi-proxy.fly.dev/basic-auth/simple");
assert_eq!( assert_eq!(
tracing_url(&req, Some(&creds)), tracing_url(&req, Some(&creds)),
"https://user:****@pypi-proxy.fly.dev/basic-auth/simple" DisplaySafeUrl::parse("https://user:password@pypi-proxy.fly.dev/basic-auth/simple")
.unwrap()
); );
} }

View file

@ -0,0 +1,49 @@
use std::sync::LazyLock;
use tracing::debug;
use url::Url;
use uv_static::EnvVars;
use crate::Credentials;
use crate::realm::{Realm, RealmRef};
/// The [`Realm`] for the Hugging Face platform.
static HUGGING_FACE_REALM: LazyLock<Realm> = LazyLock::new(|| {
let url = Url::parse("https://huggingface.co").expect("Failed to parse Hugging Face URL");
Realm::from(&url)
});
/// The authentication token for the Hugging Face platform, if set.
static HUGGING_FACE_TOKEN: LazyLock<Option<Vec<u8>>> = LazyLock::new(|| {
// Extract the Hugging Face token from the environment variable, if it exists.
let hf_token = std::env::var(EnvVars::HF_TOKEN)
.ok()
.map(String::into_bytes)
.filter(|token| !token.is_empty())?;
if std::env::var_os(EnvVars::UV_NO_HF_TOKEN).is_some() {
debug!("Ignoring Hugging Face token from environment due to `UV_NO_HF_TOKEN`");
return None;
}
debug!("Found Hugging Face token in environment");
Some(hf_token)
});
/// A provider for authentication credentials for the Hugging Face platform.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct HuggingFaceProvider;
impl HuggingFaceProvider {
/// Returns the credentials for the Hugging Face platform, if available.
pub(crate) fn credentials_for(url: &Url) -> Option<Credentials> {
if RealmRef::from(url) == *HUGGING_FACE_REALM {
if let Some(token) = HUGGING_FACE_TOKEN.as_ref() {
return Some(Credentials::Bearer {
token: token.clone(),
});
}
}
None
}
}

View file

@ -1,5 +1,5 @@
use std::hash::{Hash, Hasher};
use std::{fmt::Display, fmt::Formatter}; use std::{fmt::Display, fmt::Formatter};
use url::Url; use url::Url;
use uv_small_str::SmallString; use uv_small_str::SmallString;
@ -22,7 +22,7 @@ use uv_small_str::SmallString;
// The port is only allowed to differ if it matches the "default port" for the scheme. // The port is only allowed to differ if it matches the "default port" for the scheme.
// However, `url` (and therefore `reqwest`) sets the `port` to `None` if it matches the default port // However, `url` (and therefore `reqwest`) sets the `port` to `None` if it matches the default port
// so we do not need any special handling here. // so we do not need any special handling here.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone)]
pub(crate) struct Realm { pub(crate) struct Realm {
scheme: SmallString, scheme: SmallString,
host: Option<SmallString>, host: Option<SmallString>,
@ -59,6 +59,76 @@ impl Display for Realm {
} }
} }
impl PartialEq for Realm {
fn eq(&self, other: &Self) -> bool {
RealmRef::from(self) == RealmRef::from(other)
}
}
impl Eq for Realm {}
impl Hash for Realm {
fn hash<H: Hasher>(&self, state: &mut H) {
RealmRef::from(self).hash(state);
}
}
/// A reference to a [`Realm`] that can be used for zero-allocation comparisons.
#[derive(Debug, Copy, Clone)]
pub(crate) struct RealmRef<'a> {
scheme: &'a str,
host: Option<&'a str>,
port: Option<u16>,
}
impl<'a> From<&'a Url> for RealmRef<'a> {
fn from(url: &'a Url) -> Self {
Self {
scheme: url.scheme(),
host: url.host_str(),
port: url.port(),
}
}
}
impl PartialEq for RealmRef<'_> {
fn eq(&self, other: &Self) -> bool {
self.scheme == other.scheme && self.host == other.host && self.port == other.port
}
}
impl Eq for RealmRef<'_> {}
impl Hash for RealmRef<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.scheme.hash(state);
self.host.hash(state);
self.port.hash(state);
}
}
impl<'a> PartialEq<RealmRef<'a>> for Realm {
fn eq(&self, rhs: &RealmRef<'a>) -> bool {
RealmRef::from(self) == *rhs
}
}
impl PartialEq<Realm> for RealmRef<'_> {
fn eq(&self, rhs: &Realm) -> bool {
*self == RealmRef::from(rhs)
}
}
impl<'a> From<&'a Realm> for RealmRef<'a> {
fn from(realm: &'a Realm) -> Self {
Self {
scheme: &realm.scheme,
host: realm.host.as_deref(),
port: realm.port,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use url::{ParseError, Url}; use url::{ParseError, Url};

View file

@ -18,11 +18,6 @@ workspace = true
doctest = false doctest = false
bench = false bench = false
[[bench]]
name = "distribution-filename"
path = "benches/distribution_filename.rs"
harness = false
[[bench]] [[bench]]
name = "uv" name = "uv"
path = "benches/uv.rs" path = "benches/uv.rs"
@ -34,7 +29,6 @@ uv-client = { workspace = true }
uv-configuration = { workspace = true } uv-configuration = { workspace = true }
uv-dispatch = { workspace = true } uv-dispatch = { workspace = true }
uv-distribution = { workspace = true } uv-distribution = { workspace = true }
uv-distribution-filename = { workspace = true }
uv-distribution-types = { workspace = true } uv-distribution-types = { workspace = true }
uv-extract = { workspace = true, optional = true } uv-extract = { workspace = true, optional = true }
uv-install-wheel = { workspace = true } uv-install-wheel = { workspace = true }
@ -48,8 +42,10 @@ uv-types = { workspace = true }
uv-workspace = { workspace = true } uv-workspace = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
codspeed-criterion-compat = { version = "2.7.2", default-features = false, optional = true } codspeed-criterion-compat = { version = "3.0.2", default-features = false, optional = true }
criterion = { version = "0.5.1", default-features = false, features = ["async_tokio"] } criterion = { version = "0.7.0", default-features = false, features = [
"async_tokio",
] }
jiff = { workspace = true } jiff = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }

View file

@ -1,168 +0,0 @@
use std::str::FromStr;
use uv_bench::criterion::{
BenchmarkId, Criterion, Throughput, criterion_group, criterion_main, measurement::WallTime,
};
use uv_distribution_filename::WheelFilename;
use uv_platform_tags::{AbiTag, LanguageTag, PlatformTag, Tags};
/// A set of platform tags extracted from burntsushi's Archlinux workstation.
/// We could just re-create these via `Tags::from_env`, but those might differ
/// depending on the platform. This way, we always use the same data. It also
/// lets us assert tag compatibility regardless of where the benchmarks run.
const PLATFORM_TAGS: &[(&str, &str, &str)] = include!("../inputs/platform_tags.rs");
/// A set of wheel names used in the benchmarks below. We pick short and long
/// names, as well as compatible and not-compatibles (with `PLATFORM_TAGS`)
/// names.
///
/// The tuple is (name, filename, compatible) where `name` is a descriptive
/// name for humans used in the benchmark definition. And `filename` is the
/// actual wheel filename we want to benchmark operation on. And `compatible`
/// indicates whether the tags in the wheel filename are expected to be
/// compatible with the tags in `PLATFORM_TAGS`.
const WHEEL_NAMES: &[(&str, &str, bool)] = &[
// This tests a case with a very short name that *is* compatible with
// PLATFORM_TAGS. It only uses one tag for each component (one Python
// version, one ABI and one platform).
(
"flyte-short-compatible",
"ipython-2.1.0-py3-none-any.whl",
true,
),
// This tests a case with a long name that is *not* compatible. That
// is, all platform tags need to be checked against the tags in the
// wheel filename. This is essentially the worst possible practical
// case.
(
"flyte-long-incompatible",
"protobuf-3.5.2.post1-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl",
false,
),
// This tests a case with a long name that *is* compatible. We
// expect this to be (on average) quicker because the compatibility
// check stops as soon as a positive match is found. (Where as the
// incompatible case needs to check all tags.)
(
"flyte-long-compatible",
"coverage-6.6.0b1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
true,
),
];
/// A list of names that are candidates for wheel filenames but will ultimately
/// fail to parse.
const INVALID_WHEEL_NAMES: &[(&str, &str)] = &[
("flyte-short-extension", "mock-5.1.0.tar.gz"),
(
"flyte-long-extension",
"Pillow-5.4.0.dev0-py3.7-macosx-10.13-x86_64.egg",
),
];
/// Benchmarks the construction of platform tags.
///
/// This only happens ~once per program startup. Originally, construction was
/// trivial. But to speed up `WheelFilename::is_compatible`, we added some
/// extra processing. We thus expect construction to become slower, but we
/// write a benchmark to ensure it is still "reasonable."
fn benchmark_build_platform_tags(c: &mut Criterion<WallTime>) {
let tags: Vec<(LanguageTag, AbiTag, PlatformTag)> = PLATFORM_TAGS
.iter()
.map(|&(py, abi, plat)| {
(
LanguageTag::from_str(py).unwrap(),
AbiTag::from_str(abi).unwrap(),
PlatformTag::from_str(plat).unwrap(),
)
})
.collect();
let mut group = c.benchmark_group("build_platform_tags");
group.bench_function(BenchmarkId::from_parameter("burntsushi-archlinux"), |b| {
b.iter(|| std::hint::black_box(Tags::new(tags.clone())));
});
group.finish();
}
/// Benchmarks `WheelFilename::from_str`. This has been observed to take some
/// non-trivial time in profiling (although, at time of writing, not as much
/// as tag compatibility). In the process of optimizing tag compatibility,
/// we tweaked wheel filename parsing. This benchmark was therefore added to
/// ensure we didn't regress here.
fn benchmark_wheelname_parsing(c: &mut Criterion<WallTime>) {
let mut group = c.benchmark_group("wheelname_parsing");
for (name, filename, _) in WHEEL_NAMES.iter().copied() {
let len = u64::try_from(filename.len()).expect("length fits in u64");
group.throughput(Throughput::Bytes(len));
group.bench_function(BenchmarkId::from_parameter(name), |b| {
b.iter(|| {
filename
.parse::<WheelFilename>()
.expect("valid wheel filename");
});
});
}
group.finish();
}
/// Benchmarks `WheelFilename::from_str` when it fails. This routine is called
/// on every filename in a package's metadata. A non-trivial portion of which
/// are not wheel filenames. Ensuring that the error path is fast is thus
/// probably a good idea.
fn benchmark_wheelname_parsing_failure(c: &mut Criterion<WallTime>) {
let mut group = c.benchmark_group("wheelname_parsing_failure");
for (name, filename) in INVALID_WHEEL_NAMES.iter().copied() {
let len = u64::try_from(filename.len()).expect("length fits in u64");
group.throughput(Throughput::Bytes(len));
group.bench_function(BenchmarkId::from_parameter(name), |b| {
b.iter(|| {
filename
.parse::<WheelFilename>()
.expect_err("invalid wheel filename");
});
});
}
group.finish();
}
/// Benchmarks the `WheelFilename::is_compatible` routine. This was revealed
/// to be the #1 bottleneck in the resolver. The main issue was that the
/// set of platform tags (generated once) is quite large, and the original
/// implementation did an exhaustive search over each of them for each tag in
/// the wheel filename.
fn benchmark_wheelname_tag_compatibility(c: &mut Criterion<WallTime>) {
let tags: Vec<(LanguageTag, AbiTag, PlatformTag)> = PLATFORM_TAGS
.iter()
.map(|&(py, abi, plat)| {
(
LanguageTag::from_str(py).unwrap(),
AbiTag::from_str(abi).unwrap(),
PlatformTag::from_str(plat).unwrap(),
)
})
.collect();
let tags = Tags::new(tags);
let mut group = c.benchmark_group("wheelname_tag_compatibility");
for (name, filename, expected) in WHEEL_NAMES.iter().copied() {
let wheelname: WheelFilename = filename.parse().expect("valid wheel filename");
let len = u64::try_from(filename.len()).expect("length fits in u64");
group.throughput(Throughput::Bytes(len));
group.bench_function(BenchmarkId::from_parameter(name), |b| {
b.iter(|| {
assert_eq!(expected, wheelname.is_compatible(&tags));
});
});
}
group.finish();
}
criterion_group!(
uv_distribution_filename,
benchmark_build_platform_tags,
benchmark_wheelname_parsing,
benchmark_wheelname_parsing_failure,
benchmark_wheelname_tag_compatibility,
);
criterion_main!(uv_distribution_filename);

View file

@ -1,6 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use uv_bench::criterion::black_box; use std::hint::black_box;
use uv_bench::criterion::{Criterion, criterion_group, criterion_main, measurement::WallTime}; use uv_bench::criterion::{Criterion, criterion_group, criterion_main, measurement::WallTime};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClientBuilder; use uv_client::RegistryClientBuilder;
@ -86,12 +86,12 @@ mod resolver {
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, IndexStrategy, PreviewMode, BuildOptions, Concurrency, ConfigSettings, Constraints, IndexStrategy,
SourceStrategy, PackageConfigSettings, Preview, SourceStrategy,
}; };
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
use uv_distribution_types::{DependencyMetadata, IndexLocations}; use uv_distribution_types::{DependencyMetadata, IndexLocations, RequiresPython};
use uv_install_wheel::LinkMode; use uv_install_wheel::LinkMode;
use uv_pep440::Version; use uv_pep440::Version;
use uv_pep508::{MarkerEnvironment, MarkerEnvironmentBuilder}; use uv_pep508::{MarkerEnvironment, MarkerEnvironmentBuilder};
@ -99,7 +99,7 @@ mod resolver {
use uv_pypi_types::{Conflicts, ResolverMarkerEnvironment}; use uv_pypi_types::{Conflicts, ResolverMarkerEnvironment};
use uv_python::Interpreter; use uv_python::Interpreter;
use uv_resolver::{ use uv_resolver::{
FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement, RequiresPython, ExcludeNewer, FlatIndex, InMemoryIndex, Manifest, OptionsBuilder, PythonRequirement,
Resolver, ResolverEnvironment, ResolverOutput, Resolver, ResolverEnvironment, ResolverOutput,
}; };
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
@ -141,10 +141,12 @@ mod resolver {
universal: bool, universal: bool,
) -> Result<ResolverOutput> { ) -> Result<ResolverOutput> {
let build_isolation = BuildIsolation::default(); let build_isolation = BuildIsolation::default();
let extra_build_requires = uv_distribution::ExtraBuildRequires::default();
let build_options = BuildOptions::default(); let build_options = BuildOptions::default();
let concurrency = Concurrency::default(); let concurrency = Concurrency::default();
let config_settings = ConfigSettings::default(); let config_settings = ConfigSettings::default();
let exclude_newer = Some( let config_settings_package = PackageConfigSettings::default();
let exclude_newer = ExcludeNewer::global(
jiff::civil::date(2024, 9, 1) jiff::civil::date(2024, 9, 1)
.to_zoned(jiff::tz::TimeZone::UTC) .to_zoned(jiff::tz::TimeZone::UTC)
.unwrap() .unwrap()
@ -158,7 +160,9 @@ mod resolver {
let index = InMemoryIndex::default(); let index = InMemoryIndex::default();
let index_locations = IndexLocations::default(); let index_locations = IndexLocations::default();
let installed_packages = EmptyInstalledPackages; let installed_packages = EmptyInstalledPackages;
let options = OptionsBuilder::new().exclude_newer(exclude_newer).build(); let options = OptionsBuilder::new()
.exclude_newer(exclude_newer.clone())
.build();
let sources = SourceStrategy::default(); let sources = SourceStrategy::default();
let dependency_metadata = DependencyMetadata::default(); let dependency_metadata = DependencyMetadata::default();
let conflicts = Conflicts::empty(); let conflicts = Conflicts::empty();
@ -184,7 +188,9 @@ mod resolver {
state, state,
IndexStrategy::default(), IndexStrategy::default(),
&config_settings, &config_settings,
&config_settings_package,
build_isolation, build_isolation,
&extra_build_requires,
LinkMode::default(), LinkMode::default(),
&build_options, &build_options,
&hashes, &hashes,
@ -192,7 +198,7 @@ mod resolver {
sources, sources,
workspace_cache, workspace_cache,
concurrency, concurrency,
PreviewMode::Enabled, Preview::default(),
); );
let markers = if universal { let markers = if universal {
@ -206,6 +212,7 @@ mod resolver {
options, options,
&python_requirement, &python_requirement,
markers, markers,
interpreter.markers(),
conflicts, conflicts,
Some(&TAGS), Some(&TAGS),
&flat_index, &flat_index,

View file

@ -1,13 +1,13 @@
[package] [package]
name = "uv-build-backend" name = "uv-build-backend"
version = "0.1.0" version = "0.1.0"
edition.workspace = true edition = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
documentation.workspace = true documentation = { workspace = true }
repository.workspace = true repository = { workspace = true }
authors.workspace = true authors = { workspace = true }
license.workspace = true license = { workspace = true }
[lib] [lib]
doctest = false doctest = false
@ -31,6 +31,7 @@ flate2 = { workspace = true, default-features = false }
fs-err = { workspace = true } fs-err = { workspace = true }
globset = { workspace = true } globset = { workspace = true }
itertools = { workspace = true } itertools = { workspace = true }
rustc-hash = { workspace = true }
schemars = { workspace = true, optional = true } schemars = { workspace = true, optional = true }
serde = { workspace = true } serde = { workspace = true }
sha2 = { workspace = true } sha2 = { workspace = true }
@ -55,5 +56,6 @@ schemars = ["dep:schemars", "uv-pypi-types/schemars"]
[dev-dependencies] [dev-dependencies]
indoc = { workspace = true } indoc = { workspace = true }
insta = { version = "1.40.0", features = ["filters"] } insta = { workspace = true }
regex = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }

View file

@ -9,13 +9,12 @@ pub use settings::{BuildBackendSettings, WheelDataIncludes};
pub use source_dist::{build_source_dist, list_source_dist}; pub use source_dist::{build_source_dist, list_source_dist};
pub use wheel::{build_editable, build_wheel, list_wheel, metadata}; pub use wheel::{build_editable, build_wheel, list_wheel, metadata};
use std::fs::FileType;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use thiserror::Error; use thiserror::Error;
use tracing::debug; use tracing::debug;
use walkdir::DirEntry;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_globfilter::PortableGlobError; use uv_globfilter::PortableGlobError;
@ -23,6 +22,7 @@ use uv_normalize::PackageName;
use uv_pypi_types::{Identifier, IdentifierParseError}; use uv_pypi_types::{Identifier, IdentifierParseError};
use crate::metadata::ValidationError; use crate::metadata::ValidationError;
use crate::settings::ModuleName;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum Error { pub enum Error {
@ -32,8 +32,8 @@ pub enum Error {
Toml(#[from] toml::de::Error), Toml(#[from] toml::de::Error),
#[error("Invalid pyproject.toml")] #[error("Invalid pyproject.toml")]
Validation(#[from] ValidationError), Validation(#[from] ValidationError),
#[error(transparent)] #[error("Invalid module name: {0}")]
Identifier(#[from] IdentifierParseError), InvalidModuleName(String, #[source] IdentifierParseError),
#[error("Unsupported glob expression in: `{field}`")] #[error("Unsupported glob expression in: `{field}`")]
PortableGlob { PortableGlob {
field: String, field: String,
@ -55,33 +55,14 @@ pub enum Error {
#[source] #[source]
err: walkdir::Error, err: walkdir::Error,
}, },
#[error("Unsupported file type {:?}: `{}`", _1, _0.user_display())]
UnsupportedFileType(PathBuf, FileType),
#[error("Failed to write wheel zip archive")] #[error("Failed to write wheel zip archive")]
Zip(#[from] zip::result::ZipError), Zip(#[from] zip::result::ZipError),
#[error("Failed to write RECORD file")] #[error("Failed to write RECORD file")]
Csv(#[from] csv::Error), Csv(#[from] csv::Error),
#[error( #[error("Expected a Python module at: `{}`", _0.user_display())]
"Missing source directory at: `{}`",
_0.user_display()
)]
MissingSrc(PathBuf),
#[error(
"Expected a Python module directory at: `{}`",
_0.user_display()
)]
MissingInitPy(PathBuf), MissingInitPy(PathBuf),
#[error( #[error("For namespace packages, `__init__.py[i]` is not allowed in parent directory: `{}`", _0.user_display())]
"Missing module directory for `{}` in `{}`. Found: `{}`", NotANamespace(PathBuf),
module_name,
src_root.user_display(),
dir_listing.join("`, `")
)]
MissingModuleDir {
module_name: String,
src_root: PathBuf,
dir_listing: Vec<String>,
},
/// Either an absolute path or a parent path through `..`. /// Either an absolute path or a parent path through `..`.
#[error("Module root must be inside the project: `{}`", _0.user_display())] #[error("Module root must be inside the project: `{}`", _0.user_display())]
InvalidModuleRoot(PathBuf), InvalidModuleRoot(PathBuf),
@ -104,6 +85,16 @@ trait DirectoryWriter {
/// Files added through the method are considered generated when listing included files. /// Files added through the method are considered generated when listing included files.
fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error>; fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error>;
/// Add the file or directory to the path.
fn write_dir_entry(&mut self, entry: &DirEntry, target_path: &str) -> Result<(), Error> {
if entry.file_type().is_dir() {
self.write_directory(target_path)?;
} else {
self.write_file(target_path, entry.path())?;
}
Ok(())
}
/// Add a local file. /// Add a local file.
fn write_file(&mut self, path: &str, file: &Path) -> Result<(), Error>; fn write_file(&mut self, path: &str, file: &Path) -> Result<(), Error>;
@ -194,93 +185,166 @@ fn check_metadata_directory(
Ok(()) Ok(())
} }
/// Resolve the source root, module root and the module name. /// Returns the source root and the module path(s) with the `__init__.py[i]` below to it while
fn find_roots( /// checking the project layout and names.
source_tree: &Path,
pyproject_toml: &PyProjectToml,
relative_module_root: &Path,
module_name: Option<&Identifier>,
) -> Result<(PathBuf, PathBuf), Error> {
let relative_module_root = uv_fs::normalize_path(relative_module_root);
let src_root = source_tree.join(&relative_module_root);
if !src_root.starts_with(source_tree) {
return Err(Error::InvalidModuleRoot(relative_module_root.to_path_buf()));
}
let src_root = source_tree.join(&relative_module_root);
let module_root = find_module_root(&src_root, module_name, pyproject_toml.name())?;
Ok((src_root, module_root))
}
/// Match the module name to its module directory with potentially different casing.
/// ///
/// Some target platforms have case-sensitive filesystems, while others have case-insensitive /// Some target platforms have case-sensitive filesystems, while others have case-insensitive
/// filesystems and we always lower case the package name, our default for the module, while some /// filesystems. We always lower case the package name, our default for the module, while some
/// users want uppercase letters in their module names. For example, the package name is `pil_util`, /// users want uppercase letters in their module names. For example, the package name is `pil_util`,
/// but the module `PIL_util`. /// but the module `PIL_util`. To make the behavior as consistent as possible across platforms as
/// possible, we require that an upper case name is given explicitly through
/// `tool.uv.build-backend.module-name`.
/// ///
/// By default, the dist-info-normalized package name is the module name. For /// By default, the dist-info-normalized package name is the module name. For
/// dist-info-normalization, the rules are lowercasing, replacing `.` with `_` and /// dist-info-normalization, the rules are lowercasing, replacing `.` with `_` and
/// replace `-` with `_`. Since `.` and `-` are not allowed in identifiers, we can use a string /// replace `-` with `_`. Since `.` and `-` are not allowed in identifiers, we can use a string
/// comparison with the module name. /// comparison with the module name.
/// ///
/// To make the behavior as consistent as possible across platforms as possible, we require that an /// While we recommend one module per package, it is possible to declare a list of modules.
/// upper case name is given explicitly through `tool.uv.module-name`. fn find_roots(
source_tree: &Path,
pyproject_toml: &PyProjectToml,
relative_module_root: &Path,
module_name: Option<&ModuleName>,
namespace: bool,
) -> Result<(PathBuf, Vec<PathBuf>), Error> {
let relative_module_root = uv_fs::normalize_path(relative_module_root);
let src_root = source_tree.join(&relative_module_root);
if !src_root.starts_with(source_tree) {
return Err(Error::InvalidModuleRoot(relative_module_root.to_path_buf()));
}
let src_root = source_tree.join(&relative_module_root);
debug!("Source root: {}", src_root.user_display());
if namespace {
// `namespace = true` disables module structure checks.
let modules_relative = if let Some(module_name) = module_name {
match module_name {
ModuleName::Name(name) => {
vec![name.split('.').collect::<PathBuf>()]
}
ModuleName::Names(names) => names
.iter()
.map(|name| name.split('.').collect::<PathBuf>())
.collect(),
}
} else {
vec![PathBuf::from(
pyproject_toml.name().as_dist_info_name().to_string(),
)]
};
for module_relative in &modules_relative {
debug!("Namespace module path: {}", module_relative.user_display());
}
return Ok((src_root, modules_relative));
}
let modules_relative = if let Some(module_name) = module_name {
match module_name {
ModuleName::Name(name) => vec![module_path_from_module_name(&src_root, name)?],
ModuleName::Names(names) => names
.iter()
.map(|name| module_path_from_module_name(&src_root, name))
.collect::<Result<_, _>>()?,
}
} else {
vec![find_module_path_from_package_name(
&src_root,
pyproject_toml.name(),
)?]
};
for module_relative in &modules_relative {
debug!("Module path: {}", module_relative.user_display());
}
Ok((src_root, modules_relative))
}
/// Infer stubs packages from package name alone.
/// ///
/// Returns the module root path, the directory below which the `__init__.py` lives. /// There are potential false positives if someone had a regular package with `-stubs`.
fn find_module_root( /// The `Identifier` checks in `module_path_from_module_name` are here covered by the `PackageName`
/// validation.
fn find_module_path_from_package_name(
src_root: &Path, src_root: &Path,
module_name: Option<&Identifier>,
package_name: &PackageName, package_name: &PackageName,
) -> Result<PathBuf, Error> { ) -> Result<PathBuf, Error> {
let module_name = if let Some(module_name) = module_name { if let Some(stem) = package_name.to_string().strip_suffix("-stubs") {
// This name can be uppercase. debug!("Building stubs package instead of a regular package");
module_name.to_string() let module_name = PackageName::from_str(stem)
.expect("non-empty package name prefix must be valid package name")
.as_dist_info_name()
.to_string();
let module_relative = PathBuf::from(format!("{module_name}-stubs"));
let init_pyi = src_root.join(&module_relative).join("__init__.pyi");
if !init_pyi.is_file() {
return Err(Error::MissingInitPy(init_pyi));
}
Ok(module_relative)
} else { } else {
// Should never error, the rules for package names (in dist-info formatting) are stricter
// than those for identifiers.
// This name is always lowercase. // This name is always lowercase.
Identifier::from_str(package_name.as_dist_info_name().as_ref())?.to_string() let module_relative = PathBuf::from(package_name.as_dist_info_name().to_string());
let init_py = src_root.join(&module_relative).join("__init__.py");
if !init_py.is_file() {
return Err(Error::MissingInitPy(init_py));
}
Ok(module_relative)
}
}
/// Determine the relative module path from an explicit module name.
fn module_path_from_module_name(src_root: &Path, module_name: &str) -> Result<PathBuf, Error> {
// This name can be uppercase.
let module_relative = module_name.split('.').collect::<PathBuf>();
// Check if we have a regular module or a namespace.
let (root_name, namespace_segments) =
if let Some((root_name, namespace_segments)) = module_name.split_once('.') {
(
root_name,
namespace_segments.split('.').collect::<Vec<&str>>(),
)
} else {
(module_name, Vec::new())
}; };
let dir = match fs_err::read_dir(src_root) { // Check if we have an implementation or a stubs package.
Ok(dir_iterator) => dir_iterator.collect::<Result<Vec<_>, _>>()?, // For stubs for a namespace, the `-stubs` prefix must be on the root.
Err(err) if err.kind() == io::ErrorKind::NotFound => { let stubs = if let Some(stem) = root_name.strip_suffix("-stubs") {
return Err(Error::MissingSrc(src_root.to_path_buf())); // Check that the stubs belong to a valid module.
} Identifier::from_str(stem)
Err(err) => return Err(Error::Io(err)), .map_err(|err| Error::InvalidModuleName(module_name.to_string(), err))?;
true
} else {
Identifier::from_str(root_name)
.map_err(|err| Error::InvalidModuleName(module_name.to_string(), err))?;
false
}; };
let module_root = dir.iter().find_map(|entry| {
// TODO(konsti): Do we ever need to check if `dir/{module_name}/__init__.py` exists because // For a namespace, check that all names below the root is valid.
// the wrong casing may be recorded on disk? for segment in namespace_segments {
if entry Identifier::from_str(segment)
.file_name() .map_err(|err| Error::InvalidModuleName(module_name.to_string(), err))?;
.to_str() }
.is_some_and(|file_name| file_name == module_name)
// Check that an `__init__.py[i]` exists for the module.
let init_py =
src_root
.join(&module_relative)
.join(if stubs { "__init__.pyi" } else { "__init__.py" });
if !init_py.is_file() {
return Err(Error::MissingInitPy(init_py));
}
// For a namespace, check that the directories above the lowest are namespace directories.
for namespace_dir in module_relative.ancestors().skip(1) {
if src_root.join(namespace_dir).join("__init__.py").exists()
|| src_root.join(namespace_dir).join("__init__.pyi").exists()
{ {
Some(entry.path()) return Err(Error::NotANamespace(src_root.join(namespace_dir)));
} else {
None
} }
});
let module_root = if let Some(module_root) = module_root {
if module_root.join("__init__.py").is_file() {
module_root.clone()
} else {
return Err(Error::MissingInitPy(module_root.join("__init__.py")));
} }
} else {
return Err(Error::MissingModuleDir {
module_name,
src_root: src_root.to_path_buf(),
dir_listing: dir
.into_iter()
.filter_map(|entry| Some(entry.file_name().to_str()?.to_string()))
.collect(),
});
};
debug!("Module name: `{}`", module_name); Ok(module_relative)
Ok(module_root)
} }
#[cfg(test)] #[cfg(test)]
@ -291,12 +355,23 @@ mod tests {
use indoc::indoc; use indoc::indoc;
use insta::assert_snapshot; use insta::assert_snapshot;
use itertools::Itertools; use itertools::Itertools;
use regex::Regex;
use sha2::Digest; use sha2::Digest;
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
use std::iter;
use tempfile::TempDir; use tempfile::TempDir;
use uv_distribution_filename::{SourceDistFilename, WheelFilename}; use uv_distribution_filename::{SourceDistFilename, WheelFilename};
use uv_fs::{copy_dir_all, relative_to}; use uv_fs::{copy_dir_all, relative_to};
const MOCK_UV_VERSION: &str = "1.0.0+test";
fn format_err(err: &Error) -> String {
let context = iter::successors(std::error::Error::source(&err), |&err| err.source())
.map(|err| format!(" Caused by: {err}"))
.join("\n");
err.to_string() + "\n" + &context
}
/// File listings, generated archives and archive contents for both a build with /// File listings, generated archives and archive contents for both a build with
/// source tree -> wheel /// source tree -> wheel
/// and a build with /// and a build with
@ -316,19 +391,19 @@ mod tests {
fn build(source_root: &Path, dist: &Path) -> Result<BuildResults, Error> { fn build(source_root: &Path, dist: &Path) -> Result<BuildResults, Error> {
// Build a direct wheel, capture all its properties to compare it with the indirect wheel // Build a direct wheel, capture all its properties to compare it with the indirect wheel
// latest and remove it since it has the same filename as the indirect wheel. // latest and remove it since it has the same filename as the indirect wheel.
let (_name, direct_wheel_list_files) = list_wheel(source_root, "1.0.0+test")?; let (_name, direct_wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
let direct_wheel_filename = build_wheel(source_root, dist, None, "1.0.0+test")?; let direct_wheel_filename = build_wheel(source_root, dist, None, MOCK_UV_VERSION)?;
let direct_wheel_path = dist.join(direct_wheel_filename.to_string()); let direct_wheel_path = dist.join(direct_wheel_filename.to_string());
let direct_wheel_contents = wheel_contents(&direct_wheel_path); let direct_wheel_contents = wheel_contents(&direct_wheel_path);
let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?); let direct_wheel_hash = sha2::Sha256::digest(fs_err::read(&direct_wheel_path)?);
fs_err::remove_file(&direct_wheel_path)?; fs_err::remove_file(&direct_wheel_path)?;
// Build a source distribution. // Build a source distribution.
let (_name, source_dist_list_files) = list_source_dist(source_root, "1.0.0+test")?; let (_name, source_dist_list_files) = list_source_dist(source_root, MOCK_UV_VERSION)?;
// TODO(konsti): This should run in the unpacked source dist tempdir, but we need to // TODO(konsti): This should run in the unpacked source dist tempdir, but we need to
// normalize the path. // normalize the path.
let (_name, wheel_list_files) = list_wheel(source_root, "1.0.0+test")?; let (_name, wheel_list_files) = list_wheel(source_root, MOCK_UV_VERSION)?;
let source_dist_filename = build_source_dist(source_root, dist, "1.0.0+test")?; let source_dist_filename = build_source_dist(source_root, dist, MOCK_UV_VERSION)?;
let source_dist_path = dist.join(source_dist_filename.to_string()); let source_dist_path = dist.join(source_dist_filename.to_string());
let source_dist_contents = sdist_contents(&source_dist_path); let source_dist_contents = sdist_contents(&source_dist_path);
@ -342,7 +417,7 @@ mod tests {
source_dist_filename.name.as_dist_info_name(), source_dist_filename.name.as_dist_info_name(),
source_dist_filename.version source_dist_filename.version
)); ));
let wheel_filename = build_wheel(&sdist_top_level_directory, dist, None, "1.0.0+test")?; let wheel_filename = build_wheel(&sdist_top_level_directory, dist, None, MOCK_UV_VERSION)?;
let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string())); let wheel_contents = wheel_contents(&dist.join(wheel_filename.to_string()));
// Check that direct and indirect wheels are identical. // Check that direct and indirect wheels are identical.
@ -364,6 +439,15 @@ mod tests {
}) })
} }
fn build_err(source_root: &Path) -> String {
let dist = TempDir::new().unwrap();
let build_err = build(source_root, dist.path()).unwrap_err();
let err_message: String = format_err(&build_err)
.replace(&source_root.user_display().to_string(), "[TEMP_PATH]")
.replace('\\', "/");
err_message
}
fn sdist_contents(source_dist_path: &Path) -> Vec<String> { fn sdist_contents(source_dist_path: &Path) -> Vec<String> {
let sdist_reader = BufReader::new(File::open(source_dist_path).unwrap()); let sdist_reader = BufReader::new(File::open(source_dist_path).unwrap());
let mut source_dist = tar::Archive::new(GzDecoder::new(sdist_reader)); let mut source_dist = tar::Archive::new(GzDecoder::new(sdist_reader));
@ -434,14 +518,14 @@ mod tests {
] { ] {
copy_dir_all(built_by_uv.join(dir), src.path().join(dir)).unwrap(); copy_dir_all(built_by_uv.join(dir), src.path().join(dir)).unwrap();
} }
for dir in [ for filename in [
"pyproject.toml", "pyproject.toml",
"README.md", "README.md",
"uv.lock", "uv.lock",
"LICENSE-APACHE", "LICENSE-APACHE",
"LICENSE-MIT", "LICENSE-MIT",
] { ] {
fs_err::copy(built_by_uv.join(dir), src.path().join(dir)).unwrap(); fs_err::copy(built_by_uv.join(filename), src.path().join(filename)).unwrap();
} }
// Clear executable bit on Unix to build the same archive between Unix and Windows. // Clear executable bit on Unix to build the same archive between Unix and Windows.
@ -458,6 +542,14 @@ mod tests {
fs_err::set_permissions(&path, perms).unwrap(); fs_err::set_permissions(&path, perms).unwrap();
} }
// Redact the uv_build version to keep the hash stable across releases
let pyproject_toml = fs_err::read_to_string(src.path().join("pyproject.toml")).unwrap();
let current_requires =
Regex::new(r#"requires = \["uv_build>=[0-9.]+,<[0-9.]+"\]"#).unwrap();
let mocked_requires = r#"requires = ["uv_build>=1,<2"]"#;
let pyproject_toml = current_requires.replace(pyproject_toml.as_str(), mocked_requires);
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml.as_bytes()).unwrap();
// Add some files to be excluded // Add some files to be excluded
let module_root = src.path().join("src").join("built_by_uv"); let module_root = src.path().join("src").join("built_by_uv");
fs_err::create_dir_all(module_root.join("__pycache__")).unwrap(); fs_err::create_dir_all(module_root.join("__pycache__")).unwrap();
@ -476,7 +568,7 @@ mod tests {
// Check that the source dist is reproducible across platforms. // Check that the source dist is reproducible across platforms.
assert_snapshot!( assert_snapshot!(
format!("{:x}", sha2::Sha256::digest(fs_err::read(&source_dist_path).unwrap())), format!("{:x}", sha2::Sha256::digest(fs_err::read(&source_dist_path).unwrap())),
@"dab46bcc4d66960a11cfdc19604512a8e1a3241a67536f7e962166760e9c575c" @"871d1f859140721b67cbeaca074e7a2740c88c38028d0509eba87d1285f1da9e"
); );
// Check both the files we report and the actual files // Check both the files we report and the actual files
assert_snapshot!(format_file_list(build.source_dist_list_files, src.path()), @r" assert_snapshot!(format_file_list(build.source_dist_list_files, src.path()), @r"
@ -530,7 +622,7 @@ mod tests {
// Check that the wheel is reproducible across platforms. // Check that the wheel is reproducible across platforms.
assert_snapshot!( assert_snapshot!(
format!("{:x}", sha2::Sha256::digest(fs_err::read(&wheel_path).unwrap())), format!("{:x}", sha2::Sha256::digest(fs_err::read(&wheel_path).unwrap())),
@"ac3f68ac448023bca26de689d80401bff57f764396ae802bf4666234740ffbe3" @"342bf60c8406144f459358cde92408686c1631fe22389d042ce80379e589d6ec"
); );
assert_snapshot!(build.wheel_contents.join("\n"), @r" assert_snapshot!(build.wheel_contents.join("\n"), @r"
built_by_uv-0.1.0.data/data/ built_by_uv-0.1.0.data/data/
@ -588,7 +680,7 @@ mod tests {
license = { file = "license.txt" } license = { file = "license.txt" }
[build-system] [build-system]
requires = ["uv_build>=0.5.15,<0.6"] requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build" build-backend = "uv_build"
"# "#
}, },
@ -656,7 +748,7 @@ mod tests {
version = "1.0.0" version = "1.0.0"
[build-system] [build-system]
requires = ["uv_build>=0.5.15,<0.6"] requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build" build-backend = "uv_build"
"# "#
}, },
@ -720,7 +812,7 @@ mod tests {
version = "1.0.0" version = "1.0.0"
[build-system] [build-system]
requires = ["uv_build>=0.5.15,<0.6"] requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build" build-backend = "uv_build"
[tool.uv.build-backend] [tool.uv.build-backend]
@ -762,7 +854,7 @@ mod tests {
version = "1.0.0" version = "1.0.0"
[build-system] [build-system]
requires = ["uv_build>=0.5.15,<0.6"] requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build" build-backend = "uv_build"
[tool.uv.build-backend] [tool.uv.build-backend]
@ -787,7 +879,7 @@ mod tests {
version = "1.0.0" version = "1.0.0"
[build-system] [build-system]
requires = ["uv_build>=0.5.15,<0.6"] requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build" build-backend = "uv_build"
[tool.uv.build-backend] [tool.uv.build-backend]
@ -818,13 +910,454 @@ mod tests {
) )
.unwrap(); .unwrap();
let build_err = build(src.path(), dist.path()).unwrap_err(); let build_err = build(src.path(), dist.path()).unwrap_err();
let err_message = build_err let err_message = format_err(&build_err)
.to_string()
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]") .replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
.replace('\\', "/"); .replace('\\', "/");
assert_snapshot!( assert_snapshot!(
err_message, err_message,
@"Missing module directory for `camel_case` in `[TEMP_PATH]/src`. Found: `camelCase`" @"Expected a Python module at: `[TEMP_PATH]/src/camel_case/__init__.py`"
); );
} }
#[test]
fn invalid_stubs_name() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "camelcase"
version = "1.0.0"
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
[tool.uv.build-backend]
module-name = "django@home-stubs"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
let dist = TempDir::new().unwrap();
let build_err = build(src.path(), dist.path()).unwrap_err();
let err_message = format_err(&build_err);
assert_snapshot!(
err_message,
@r"
Invalid module name: django@home-stubs
Caused by: Invalid character `@` at position 7 for identifier `django@home`, expected an underscore or an alphanumeric character
"
);
}
/// Stubs packages use a special name and `__init__.pyi`.
#[test]
fn stubs_package() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "stuffed-bird-stubs"
version = "1.0.0"
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
fs_err::create_dir_all(src.path().join("src").join("stuffed_bird-stubs")).unwrap();
// That's the wrong file, we're expecting a `__init__.pyi`.
let regular_init_py = src
.path()
.join("src")
.join("stuffed_bird-stubs")
.join("__init__.py");
File::create(&regular_init_py).unwrap();
let dist = TempDir::new().unwrap();
let build_err = build(src.path(), dist.path()).unwrap_err();
let err_message = format_err(&build_err)
.replace(&src.path().user_display().to_string(), "[TEMP_PATH]")
.replace('\\', "/");
assert_snapshot!(
err_message,
@"Expected a Python module at: `[TEMP_PATH]/src/stuffed_bird-stubs/__init__.pyi`"
);
// Create the correct file
fs_err::remove_file(regular_init_py).unwrap();
File::create(
src.path()
.join("src")
.join("stuffed_bird-stubs")
.join("__init__.pyi"),
)
.unwrap();
let build1 = build(src.path(), dist.path()).unwrap();
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
stuffed_bird-stubs/
stuffed_bird-stubs/__init__.pyi
stuffed_bird_stubs-1.0.0.dist-info/
stuffed_bird_stubs-1.0.0.dist-info/METADATA
stuffed_bird_stubs-1.0.0.dist-info/RECORD
stuffed_bird_stubs-1.0.0.dist-info/WHEEL
");
// Check that setting the name manually works equally.
let pyproject_toml = indoc! {r#"
[project]
name = "stuffed-bird-stubs"
version = "1.0.0"
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
[tool.uv.build-backend]
module-name = "stuffed_bird-stubs"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
let build2 = build(src.path(), dist.path()).unwrap();
assert_eq!(build1.wheel_contents, build2.wheel_contents);
}
/// A simple namespace package with a single root `__init__.py`.
#[test]
fn simple_namespace_package() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "simple-namespace-part"
version = "1.0.0"
[tool.uv.build-backend]
module-name = "simple_namespace.part"
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
fs_err::create_dir_all(src.path().join("src").join("simple_namespace").join("part"))
.unwrap();
assert_snapshot!(
build_err(src.path()),
@"Expected a Python module at: `[TEMP_PATH]/src/simple_namespace/part/__init__.py`"
);
// Create the correct file
File::create(
src.path()
.join("src")
.join("simple_namespace")
.join("part")
.join("__init__.py"),
)
.unwrap();
// For a namespace package, there must not be an `__init__.py` here.
let bogus_init_py = src
.path()
.join("src")
.join("simple_namespace")
.join("__init__.py");
File::create(&bogus_init_py).unwrap();
assert_snapshot!(
build_err(src.path()),
@"For namespace packages, `__init__.py[i]` is not allowed in parent directory: `[TEMP_PATH]/src/simple_namespace`"
);
fs_err::remove_file(bogus_init_py).unwrap();
let dist = TempDir::new().unwrap();
let build1 = build(src.path(), dist.path()).unwrap();
assert_snapshot!(build1.source_dist_contents.join("\n"), @r"
simple_namespace_part-1.0.0/
simple_namespace_part-1.0.0/PKG-INFO
simple_namespace_part-1.0.0/pyproject.toml
simple_namespace_part-1.0.0/src
simple_namespace_part-1.0.0/src/simple_namespace
simple_namespace_part-1.0.0/src/simple_namespace/part
simple_namespace_part-1.0.0/src/simple_namespace/part/__init__.py
");
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
simple_namespace/
simple_namespace/part/
simple_namespace/part/__init__.py
simple_namespace_part-1.0.0.dist-info/
simple_namespace_part-1.0.0.dist-info/METADATA
simple_namespace_part-1.0.0.dist-info/RECORD
simple_namespace_part-1.0.0.dist-info/WHEEL
");
// Check that `namespace = true` works too.
let pyproject_toml = indoc! {r#"
[project]
name = "simple-namespace-part"
version = "1.0.0"
[tool.uv.build-backend]
module-name = "simple_namespace.part"
namespace = true
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
let build2 = build(src.path(), dist.path()).unwrap();
assert_eq!(build1, build2);
}
/// A complex namespace package with a multiple root `__init__.py`.
#[test]
fn complex_namespace_package() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "complex-namespace"
version = "1.0.0"
[tool.uv.build-backend]
namespace = true
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
fs_err::create_dir_all(
src.path()
.join("src")
.join("complex_namespace")
.join("part_a"),
)
.unwrap();
File::create(
src.path()
.join("src")
.join("complex_namespace")
.join("part_a")
.join("__init__.py"),
)
.unwrap();
fs_err::create_dir_all(
src.path()
.join("src")
.join("complex_namespace")
.join("part_b"),
)
.unwrap();
File::create(
src.path()
.join("src")
.join("complex_namespace")
.join("part_b")
.join("__init__.py"),
)
.unwrap();
let dist = TempDir::new().unwrap();
let build1 = build(src.path(), dist.path()).unwrap();
assert_snapshot!(build1.wheel_contents.join("\n"), @r"
complex_namespace-1.0.0.dist-info/
complex_namespace-1.0.0.dist-info/METADATA
complex_namespace-1.0.0.dist-info/RECORD
complex_namespace-1.0.0.dist-info/WHEEL
complex_namespace/
complex_namespace/part_a/
complex_namespace/part_a/__init__.py
complex_namespace/part_b/
complex_namespace/part_b/__init__.py
");
// Check that setting the name manually works equally.
let pyproject_toml = indoc! {r#"
[project]
name = "complex-namespace"
version = "1.0.0"
[tool.uv.build-backend]
module-name = "complex_namespace"
namespace = true
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
let build2 = build(src.path(), dist.path()).unwrap();
assert_eq!(build1, build2);
}
/// Stubs for a namespace package.
#[test]
fn stubs_namespace() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "cloud.db.schema-stubs"
version = "1.0.0"
[tool.uv.build-backend]
module-name = "cloud-stubs.db.schema"
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
fs_err::create_dir_all(
src.path()
.join("src")
.join("cloud-stubs")
.join("db")
.join("schema"),
)
.unwrap();
File::create(
src.path()
.join("src")
.join("cloud-stubs")
.join("db")
.join("schema")
.join("__init__.pyi"),
)
.unwrap();
let dist = TempDir::new().unwrap();
let build = build(src.path(), dist.path()).unwrap();
assert_snapshot!(build.wheel_contents.join("\n"), @r"
cloud-stubs/
cloud-stubs/db/
cloud-stubs/db/schema/
cloud-stubs/db/schema/__init__.pyi
cloud_db_schema_stubs-1.0.0.dist-info/
cloud_db_schema_stubs-1.0.0.dist-info/METADATA
cloud_db_schema_stubs-1.0.0.dist-info/RECORD
cloud_db_schema_stubs-1.0.0.dist-info/WHEEL
");
}
/// A package with multiple modules, one a regular module and two namespace modules.
#[test]
fn multiple_module_names() {
let src = TempDir::new().unwrap();
let pyproject_toml = indoc! {r#"
[project]
name = "simple-namespace-part"
version = "1.0.0"
[tool.uv.build-backend]
module-name = ["foo", "simple_namespace.part_a", "simple_namespace.part_b"]
[build-system]
requires = ["uv_build>=0.5.15,<0.6.0"]
build-backend = "uv_build"
"#
};
fs_err::write(src.path().join("pyproject.toml"), pyproject_toml).unwrap();
fs_err::create_dir_all(src.path().join("src").join("foo")).unwrap();
fs_err::create_dir_all(
src.path()
.join("src")
.join("simple_namespace")
.join("part_a"),
)
.unwrap();
fs_err::create_dir_all(
src.path()
.join("src")
.join("simple_namespace")
.join("part_b"),
)
.unwrap();
// Most of these checks exist in other tests too, but we want to ensure that they apply
// with multiple modules too.
// The first module is missing an `__init__.py`.
assert_snapshot!(
build_err(src.path()),
@"Expected a Python module at: `[TEMP_PATH]/src/foo/__init__.py`"
);
// Create the first correct `__init__.py` file
File::create(src.path().join("src").join("foo").join("__init__.py")).unwrap();
// The second module, a namespace, is missing an `__init__.py`.
assert_snapshot!(
build_err(src.path()),
@"Expected a Python module at: `[TEMP_PATH]/src/simple_namespace/part_a/__init__.py`"
);
// Create the other two correct `__init__.py` files
File::create(
src.path()
.join("src")
.join("simple_namespace")
.join("part_a")
.join("__init__.py"),
)
.unwrap();
File::create(
src.path()
.join("src")
.join("simple_namespace")
.join("part_b")
.join("__init__.py"),
)
.unwrap();
// For the second module, a namespace, there must not be an `__init__.py` here.
let bogus_init_py = src
.path()
.join("src")
.join("simple_namespace")
.join("__init__.py");
File::create(&bogus_init_py).unwrap();
assert_snapshot!(
build_err(src.path()),
@"For namespace packages, `__init__.py[i]` is not allowed in parent directory: `[TEMP_PATH]/src/simple_namespace`"
);
fs_err::remove_file(bogus_init_py).unwrap();
let dist = TempDir::new().unwrap();
let build = build(src.path(), dist.path()).unwrap();
assert_snapshot!(build.source_dist_contents.join("\n"), @r"
simple_namespace_part-1.0.0/
simple_namespace_part-1.0.0/PKG-INFO
simple_namespace_part-1.0.0/pyproject.toml
simple_namespace_part-1.0.0/src
simple_namespace_part-1.0.0/src/foo
simple_namespace_part-1.0.0/src/foo/__init__.py
simple_namespace_part-1.0.0/src/simple_namespace
simple_namespace_part-1.0.0/src/simple_namespace/part_a
simple_namespace_part-1.0.0/src/simple_namespace/part_a/__init__.py
simple_namespace_part-1.0.0/src/simple_namespace/part_b
simple_namespace_part-1.0.0/src/simple_namespace/part_b/__init__.py
");
assert_snapshot!(build.wheel_contents.join("\n"), @r"
foo/
foo/__init__.py
simple_namespace/
simple_namespace/part_a/
simple_namespace/part_a/__init__.py
simple_namespace/part_b/
simple_namespace/part_b/__init__.py
simple_namespace_part-1.0.0.dist-info/
simple_namespace_part-1.0.0.dist-info/METADATA
simple_namespace_part-1.0.0.dist-info/RECORD
simple_namespace_part-1.0.0.dist-info/WHEEL
");
}
} }

View file

@ -7,7 +7,7 @@ use std::str::FromStr;
use itertools::Itertools; use itertools::Itertools;
use serde::Deserialize; use serde::Deserialize;
use tracing::{debug, trace}; use tracing::{debug, trace, warn};
use version_ranges::Ranges; use version_ranges::Ranges;
use walkdir::WalkDir; use walkdir::WalkDir;
@ -54,10 +54,6 @@ pub enum ValidationError {
"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `{0}`" "Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `{0}`"
)] )]
InvalidGroup(String), InvalidGroup(String),
#[error(
"Entrypoint names must consist of letters, numbers, dots, underscores and dashes; invalid name: `{0}`"
)]
InvalidName(String),
#[error("Use `project.scripts` instead of `project.entry-points.console_scripts`")] #[error("Use `project.scripts` instead of `project.entry-points.console_scripts`")]
ReservedScripts, ReservedScripts,
#[error("Use `project.gui-scripts` instead of `project.entry-points.gui_scripts`")] #[error("Use `project.gui-scripts` instead of `project.entry-points.gui_scripts`")]
@ -171,7 +167,7 @@ impl PyProjectToml {
/// ///
/// ```toml /// ```toml
/// [build-system] /// [build-system]
/// requires = ["uv_build>=0.4.15,<5"] /// requires = ["uv_build>=0.4.15,<0.5.0"]
/// build-backend = "uv_build" /// build-backend = "uv_build"
/// ``` /// ```
pub fn check_build_system(&self, uv_version: &str) -> Vec<String> { pub fn check_build_system(&self, uv_version: &str) -> Vec<String> {
@ -620,12 +616,14 @@ impl PyProjectToml {
let _ = writeln!(writer, "[{group}]"); let _ = writeln!(writer, "[{group}]");
for (name, object_reference) in entries { for (name, object_reference) in entries {
// More strict than the spec, we enforce the recommendation
if !name if !name
.chars() .chars()
.all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '_') .all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '_')
{ {
return Err(ValidationError::InvalidName(name.to_string())); warn!(
"Entrypoint names should consist of letters, numbers, dots, underscores and \
dashes; non-compliant name: `{name}`"
);
} }
// TODO(konsti): Validate that the object references are valid Python identifiers. // TODO(konsti): Validate that the object references are valid Python identifiers.
@ -703,7 +701,7 @@ struct Project {
/// The optional `project.readme` key in a pyproject.toml as specified in /// The optional `project.readme` key in a pyproject.toml as specified in
/// <https://packaging.python.org/en/latest/specifications/pyproject-toml/#readme>. /// <https://packaging.python.org/en/latest/specifications/pyproject-toml/#readme>.
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(untagged, rename_all = "kebab-case")] #[serde(untagged, rename_all_fields = "kebab-case")]
pub(crate) enum Readme { pub(crate) enum Readme {
/// Relative path to the README. /// Relative path to the README.
String(PathBuf), String(PathBuf),
@ -713,7 +711,7 @@ pub(crate) enum Readme {
content_type: String, content_type: String,
charset: Option<String>, charset: Option<String>,
}, },
/// The full description of the project as inline value. /// The full description of the project as an inline value.
Text { Text {
text: String, text: String,
content_type: String, content_type: String,
@ -826,7 +824,7 @@ mod tests {
{payload} {payload}
[build-system] [build-system]
requires = ["uv_build>=0.4.15,<5"] requires = ["uv_build>=0.4.15,<0.5.0"]
build-backend = "uv_build" build-backend = "uv_build"
"# "#
} }
@ -909,7 +907,7 @@ mod tests {
foo-bar = "foo:bar" foo-bar = "foo:bar"
[build-system] [build-system]
requires = ["uv_build>=0.4.15,<5"] requires = ["uv_build>=0.4.15,<0.5.0"]
build-backend = "uv_build" build-backend = "uv_build"
"# "#
}; };
@ -965,6 +963,65 @@ mod tests {
"###); "###);
} }
#[test]
fn readme() {
let temp_dir = TempDir::new().unwrap();
fs_err::write(
temp_dir.path().join("Readme.md"),
indoc! {r"
# Foo
This is the foo library.
"},
)
.unwrap();
fs_err::write(
temp_dir.path().join("License.txt"),
indoc! {r#"
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#},
)
.unwrap();
let contents = indoc! {r#"
# See https://github.com/pypa/sampleproject/blob/main/pyproject.toml for another example
[project]
name = "hello-world"
version = "0.1.0"
description = "A Python package"
readme = { file = "Readme.md", content-type = "text/markdown" }
requires_python = ">=3.12"
[build-system]
requires = ["uv_build>=0.4.15,<0.5"]
build-backend = "uv_build"
"#
};
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
assert_snapshot!(metadata.core_metadata_format(), @r"
Metadata-Version: 2.3
Name: hello-world
Version: 0.1.0
Summary: A Python package
Description-Content-Type: text/markdown
# Foo
This is the foo library.
");
}
#[test] #[test]
fn self_extras() { fn self_extras() {
let temp_dir = TempDir::new().unwrap(); let temp_dir = TempDir::new().unwrap();
@ -1036,7 +1093,7 @@ mod tests {
foo-bar = "foo:bar" foo-bar = "foo:bar"
[build-system] [build-system]
requires = ["uv_build>=0.4.15,<5"] requires = ["uv_build>=0.4.15,<0.5.0"]
build-backend = "uv_build" build-backend = "uv_build"
"# "#
}; };
@ -1104,7 +1161,7 @@ mod tests {
let contents = extend_project(""); let contents = extend_project("");
let pyproject_toml = PyProjectToml::parse(&contents).unwrap(); let pyproject_toml = PyProjectToml::parse(&contents).unwrap();
assert_snapshot!( assert_snapshot!(
pyproject_toml.check_build_system("1.0.0+test").join("\n"), pyproject_toml.check_build_system("0.4.15+test").join("\n"),
@"" @""
); );
} }
@ -1135,7 +1192,7 @@ mod tests {
version = "0.1.0" version = "0.1.0"
[build-system] [build-system]
requires = ["uv_build>=0.4.15,<5", "wheel"] requires = ["uv_build>=0.4.15,<0.5.0", "wheel"]
build-backend = "uv_build" build-backend = "uv_build"
"#}; "#};
let pyproject_toml = PyProjectToml::parse(contents).unwrap(); let pyproject_toml = PyProjectToml::parse(contents).unwrap();
@ -1171,7 +1228,7 @@ mod tests {
version = "0.1.0" version = "0.1.0"
[build-system] [build-system]
requires = ["uv_build>=0.4.15,<5"] requires = ["uv_build>=0.4.15,<0.5.0"]
build-backend = "setuptools" build-backend = "setuptools"
"#}; "#};
let pyproject_toml = PyProjectToml::parse(contents).unwrap(); let pyproject_toml = PyProjectToml::parse(contents).unwrap();
@ -1344,16 +1401,6 @@ mod tests {
assert_snapshot!(script_error(&contents), @"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `a@b`"); assert_snapshot!(script_error(&contents), @"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `a@b`");
} }
#[test]
fn invalid_entry_point_name() {
let contents = extend_project(indoc! {r#"
[project.scripts]
"a@b" = "bar"
"#
});
assert_snapshot!(script_error(&contents), @"Entrypoint names must consist of letters, numbers, dots, underscores and dashes; invalid name: `a@b`");
}
#[test] #[test]
fn invalid_entry_point_conflict_scripts() { fn invalid_entry_point_conflict_scripts() {
let contents = extend_project(indoc! {r#" let contents = extend_project(indoc! {r#"

View file

@ -1,14 +1,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use uv_macros::OptionsMetadata; use uv_macros::OptionsMetadata;
use uv_pypi_types::Identifier;
/// Settings for the uv build backend (`uv_build`). /// Settings for the uv build backend (`uv_build`).
/// ///
/// !!! note
///
/// The uv build backend is currently in preview and may change in any future release.
///
/// Note that those settings only apply when using the `uv_build` backend, other build backends /// Note that those settings only apply when using the `uv_build` backend, other build backends
/// (such as hatchling) have their own configuration. /// (such as hatchling) have their own configuration.
/// ///
@ -32,15 +27,26 @@ pub struct BuildBackendSettings {
/// ///
/// The default module name is the package name with dots and dashes replaced by underscores. /// The default module name is the package name with dots and dashes replaced by underscores.
/// ///
/// Package names need to be valid Python identifiers, and the directory needs to contain a
/// `__init__.py`. An exception are stubs packages, whose name ends with `-stubs`, with the stem
/// being the module name, and which contain a `__init__.pyi` file.
///
/// For namespace packages with a single module, the path can be dotted, e.g., `foo.bar` or
/// `foo-stubs.bar`.
///
/// For namespace packages with multiple modules, the path can be a list, e.g.,
/// `["foo", "bar"]`. We recommend using a single module per package, splitting multiple
/// packages into a workspace.
///
/// Note that using this option runs the risk of creating two packages with different names but /// Note that using this option runs the risk of creating two packages with different names but
/// the same module names. Installing such packages together leads to unspecified behavior, /// the same module names. Installing such packages together leads to unspecified behavior,
/// often with corrupted files or directory trees. /// often with corrupted files or directory trees.
#[option( #[option(
default = r#"None"#, default = r#"None"#,
value_type = "str", value_type = "str | list[str]",
example = r#"module-name = "sklearn""# example = r#"module-name = "sklearn""#
)] )]
pub module_name: Option<Identifier>, pub module_name: Option<ModuleName>,
/// Glob expressions which files and directories to additionally include in the source /// Glob expressions which files and directories to additionally include in the source
/// distribution. /// distribution.
@ -79,6 +85,56 @@ pub struct BuildBackendSettings {
)] )]
pub wheel_exclude: Vec<String>, pub wheel_exclude: Vec<String>,
/// Build a namespace package.
///
/// Build a PEP 420 implicit namespace package, allowing more than one root `__init__.py`.
///
/// Use this option when the namespace package contains multiple root `__init__.py`, for
/// namespace packages with a single root `__init__.py` use a dotted `module-name` instead.
///
/// To compare dotted `module-name` and `namespace = true`, the first example below can be
/// expressed with `module-name = "cloud.database"`: There is one root `__init__.py` `database`.
/// In the second example, we have three roots (`cloud.database`, `cloud.database_pro`,
/// `billing.modules.database_pro`), so `namespace = true` is required.
///
/// ```text
/// src
/// └── cloud
/// └── database
/// ├── __init__.py
/// ├── query_builder
/// │ └── __init__.py
/// └── sql
/// ├── parser.py
/// └── __init__.py
/// ```
///
/// ```text
/// src
/// ├── cloud
/// │ ├── database
/// │ │ ├── __init__.py
/// │ │ ├── query_builder
/// │ │ │ └── __init__.py
/// │ │ └── sql
/// │ │ ├── __init__.py
/// │ │ └── parser.py
/// │ └── database_pro
/// │ ├── __init__.py
/// │ └── query_builder.py
/// └── billing
/// └── modules
/// └── database_pro
/// ├── __init__.py
/// └── sql.py
/// ```
#[option(
default = r#"false"#,
value_type = "bool",
example = r#"namespace = true"#
)]
pub namespace: bool,
/// Data includes for wheels. /// Data includes for wheels.
/// ///
/// Each entry is a directory, whose contents are copied to the matching directory in the wheel /// Each entry is a directory, whose contents are copied to the matching directory in the wheel
@ -99,7 +155,7 @@ pub struct BuildBackendSettings {
/// with this package as build requirement use the include directory to find additional header /// with this package as build requirement use the include directory to find additional header
/// files. /// files.
/// - `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended /// - `purelib` and `platlib`: Installed to the `site-packages` directory. It is not recommended
/// to uses these two options. /// to use these two options.
// TODO(konsti): We should show a flat example instead. // TODO(konsti): We should show a flat example instead.
// ```toml // ```toml
// [tool.uv.build-backend.data] // [tool.uv.build-backend.data]
@ -109,7 +165,7 @@ pub struct BuildBackendSettings {
#[option( #[option(
default = r#"{}"#, default = r#"{}"#,
value_type = "dict[str, str]", value_type = "dict[str, str]",
example = r#"data = { "headers": "include/headers", "scripts": "bin" }"# example = r#"data = { headers = "include/headers", scripts = "bin" }"#
)] )]
pub data: WheelDataIncludes, pub data: WheelDataIncludes,
} }
@ -123,11 +179,23 @@ impl Default for BuildBackendSettings {
default_excludes: true, default_excludes: true,
source_exclude: Vec::new(), source_exclude: Vec::new(),
wheel_exclude: Vec::new(), wheel_exclude: Vec::new(),
namespace: false,
data: WheelDataIncludes::default(), data: WheelDataIncludes::default(),
} }
} }
} }
/// Whether to include a single module or multiple modules.
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(untagged)]
pub enum ModuleName {
/// A single module name.
Name(String),
/// Multiple module names, which are all included.
Names(Vec<String>),
}
/// Data includes for wheels. /// Data includes for wheels.
/// ///
/// See `BuildBackendSettings::data`. /// See `BuildBackendSettings::data`.

View file

@ -68,20 +68,24 @@ fn source_dist_matcher(
includes.push(globset::escape("pyproject.toml")); includes.push(globset::escape("pyproject.toml"));
// Check that the source tree contains a module. // Check that the source tree contains a module.
let (_, module_root) = find_roots( let (src_root, modules_relative) = find_roots(
source_tree, source_tree,
pyproject_toml, pyproject_toml,
&settings.module_root, &settings.module_root,
settings.module_name.as_ref(), settings.module_name.as_ref(),
settings.namespace,
)?; )?;
for module_relative in modules_relative {
// The wheel must not include any files included by the source distribution (at least until we // The wheel must not include any files included by the source distribution (at least until we
// have files generated in the source dist -> wheel build step). // have files generated in the source dist -> wheel build step).
let import_path = uv_fs::normalize_path( let import_path = uv_fs::normalize_path(
&uv_fs::relative_to(module_root, source_tree).expect("module root is inside source tree"), &uv_fs::relative_to(src_root.join(module_relative), source_tree)
.expect("module root is inside source tree"),
) )
.portable_display() .portable_display()
.to_string(); .to_string();
includes.push(format!("{}/**", globset::escape(&import_path))); includes.push(format!("{}/**", globset::escape(&import_path)));
}
for include in includes { for include in includes {
let glob = PortableGlobParser::Uv let glob = PortableGlobParser::Uv
.parse(&include) .parse(&include)
@ -248,32 +252,16 @@ fn write_source_dist(
.expect("walkdir starts with root"); .expect("walkdir starts with root");
if !include_matcher.match_path(relative) || exclude_matcher.is_match(relative) { if !include_matcher.match_path(relative) || exclude_matcher.is_match(relative) {
trace!("Excluding: `{}`", relative.user_display()); trace!("Excluding from sdist: `{}`", relative.user_display());
continue; continue;
} }
debug!("Including {}", relative.user_display()); let entry_path = Path::new(&top_level)
if entry.file_type().is_dir() {
writer.write_directory(
&Path::new(&top_level)
.join(relative) .join(relative)
.portable_display() .portable_display()
.to_string(), .to_string();
)?; debug!("Adding to sdist: {}", relative.user_display());
} else if entry.file_type().is_file() { writer.write_dir_entry(&entry, &entry_path)?;
writer.write_file(
&Path::new(&top_level)
.join(relative)
.portable_display()
.to_string(),
entry.path(),
)?;
} else {
return Err(Error::UnsupportedFileType(
relative.to_path_buf(),
entry.file_type(),
));
}
} }
debug!("Visited {files_visited} files for source dist build"); debug!("Visited {files_visited} files for source dist build");

View file

@ -1,6 +1,7 @@
use fs_err::File; use fs_err::File;
use globset::{GlobSet, GlobSetBuilder}; use globset::{GlobSet, GlobSetBuilder};
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::io::{BufReader, Read, Write}; use std::io::{BufReader, Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -17,8 +18,7 @@ use uv_warnings::warn_user_once;
use crate::metadata::DEFAULT_EXCLUDES; use crate::metadata::DEFAULT_EXCLUDES;
use crate::{ use crate::{
BuildBackendSettings, DirectoryWriter, Error, FileList, ListWriter, PyProjectToml, BuildBackendSettings, DirectoryWriter, Error, FileList, ListWriter, PyProjectToml, find_roots,
find_module_root, find_roots,
}; };
/// Build a wheel from the source tree and place it in the output directory. /// Build a wheel from the source tree and place it in the output directory.
@ -124,15 +124,29 @@ fn write_wheel(
let exclude_matcher = build_exclude_matcher(excludes)?; let exclude_matcher = build_exclude_matcher(excludes)?;
debug!("Adding content files to wheel"); debug!("Adding content files to wheel");
let (src_root, module_root) = find_roots( let (src_root, module_relative) = find_roots(
source_tree, source_tree,
pyproject_toml, pyproject_toml,
&settings.module_root, &settings.module_root,
settings.module_name.as_ref(), settings.module_name.as_ref(),
settings.namespace,
)?; )?;
let mut files_visited = 0; let mut files_visited = 0;
for entry in WalkDir::new(module_root) let mut prefix_directories = FxHashSet::default();
for module_relative in module_relative {
// For convenience, have directories for the whole tree in the wheel
for ancestor in module_relative.ancestors().skip(1) {
if ancestor == Path::new("") {
continue;
}
// Avoid duplicate directories in the zip.
if prefix_directories.insert(ancestor.to_path_buf()) {
wheel_writer.write_directory(&ancestor.portable_display().to_string())?;
}
}
for entry in WalkDir::new(src_root.join(module_relative))
.sort_by_file_name() .sort_by_file_name()
.into_iter() .into_iter()
.filter_entry(|entry| !exclude_matcher.is_match(entry.path())) .filter_entry(|entry| !exclude_matcher.is_match(entry.path()))
@ -156,7 +170,7 @@ fn write_wheel(
.path() .path()
.strip_prefix(source_tree) .strip_prefix(source_tree)
.expect("walkdir starts with root"); .expect("walkdir starts with root");
let wheel_path = entry let entry_path = entry
.path() .path()
.strip_prefix(&src_root) .strip_prefix(&src_root)
.expect("walkdir starts with root"); .expect("walkdir starts with root");
@ -164,20 +178,10 @@ fn write_wheel(
trace!("Excluding from module: `{}`", match_path.user_display()); trace!("Excluding from module: `{}`", match_path.user_display());
continue; continue;
} }
let wheel_path = wheel_path.portable_display().to_string();
debug!("Adding to wheel: `{wheel_path}`"); let entry_path = entry_path.portable_display().to_string();
debug!("Adding to wheel: {entry_path}");
if entry.file_type().is_dir() { wheel_writer.write_dir_entry(&entry, &entry_path)?;
wheel_writer.write_directory(&wheel_path)?;
} else if entry.file_type().is_file() {
wheel_writer.write_file(&wheel_path, entry.path())?;
} else {
// TODO(konsti): We may want to support symlinks, there is support for installing them.
return Err(Error::UnsupportedFileType(
entry.path().to_path_buf(),
entry.file_type(),
));
} }
} }
debug!("Visited {files_visited} files for wheel build"); debug!("Visited {files_visited} files for wheel build");
@ -267,16 +271,13 @@ pub fn build_editable(
let mut wheel_writer = ZipDirectoryWriter::new_wheel(File::create(&wheel_path)?); let mut wheel_writer = ZipDirectoryWriter::new_wheel(File::create(&wheel_path)?);
debug!("Adding pth file to {}", wheel_path.user_display()); debug!("Adding pth file to {}", wheel_path.user_display());
let src_root = source_tree.join(&settings.module_root);
if !src_root.starts_with(source_tree) {
return Err(Error::InvalidModuleRoot(settings.module_root.clone()));
}
// Check that a module root exists in the directory we're linking from the `.pth` file // Check that a module root exists in the directory we're linking from the `.pth` file
find_module_root( let (src_root, _module_relative) = find_roots(
&src_root, source_tree,
&pyproject_toml,
&settings.module_root,
settings.module_name.as_ref(), settings.module_name.as_ref(),
pyproject_toml.name(), settings.namespace,
)?; )?;
wheel_writer.write_bytes( wheel_writer.write_bytes(
@ -514,23 +515,12 @@ fn wheel_subdir_from_globs(
continue; continue;
} }
let relative_licenses = Path::new(target) let license_path = Path::new(target)
.join(relative) .join(relative)
.portable_display() .portable_display()
.to_string(); .to_string();
debug!("Adding for {}: `{}`", globs_field, relative.user_display());
if entry.file_type().is_dir() { wheel_writer.write_dir_entry(&entry, &license_path)?;
wheel_writer.write_directory(&relative_licenses)?;
} else if entry.file_type().is_file() {
debug!("Adding {} file: `{}`", globs_field, relative.user_display());
wheel_writer.write_file(&relative_licenses, entry.path())?;
} else {
// TODO(konsti): We may want to support symlinks, there is support for installing them.
return Err(Error::UnsupportedFileType(
entry.path().to_path_buf(),
entry.file_type(),
));
}
} }
Ok(()) Ok(())
} }
@ -631,8 +621,8 @@ impl ZipDirectoryWriter {
path: &str, path: &str,
executable_bit: bool, executable_bit: bool,
) -> Result<Box<dyn Write + 'slf>, Error> { ) -> Result<Box<dyn Write + 'slf>, Error> {
// 644 is the default of the zip crate. // Set file permissions: 644 (rw-r--r--) for regular files, 755 (rwxr-xr-x) for executables
let permissions = if executable_bit { 775 } else { 664 }; let permissions = if executable_bit { 0o755 } else { 0o644 };
let options = zip::write::SimpleFileOptions::default() let options = zip::write::SimpleFileOptions::default()
.unix_permissions(permissions) .unix_permissions(permissions)
.compression_method(self.compression); .compression_method(self.compression);
@ -644,7 +634,10 @@ impl ZipDirectoryWriter {
impl DirectoryWriter for ZipDirectoryWriter { impl DirectoryWriter for ZipDirectoryWriter {
fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error> { fn write_bytes(&mut self, path: &str, bytes: &[u8]) -> Result<(), Error> {
trace!("Adding {}", path); trace!("Adding {}", path);
let options = zip::write::SimpleFileOptions::default().compression_method(self.compression); // Set appropriate permissions for metadata files (644 = rw-r--r--)
let options = zip::write::SimpleFileOptions::default()
.unix_permissions(0o644)
.compression_method(self.compression);
self.writer.start_file(path, options)?; self.writer.start_file(path, options)?;
self.writer.write_all(bytes)?; self.writer.write_all(bytes)?;

View file

@ -17,6 +17,7 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
uv-cache-key = { workspace = true }
uv-configuration = { workspace = true } uv-configuration = { workspace = true }
uv-distribution = { workspace = true } uv-distribution = { workspace = true }
uv-distribution-types = { workspace = true } uv-distribution-types = { workspace = true }
@ -47,4 +48,4 @@ tracing = { workspace = true }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
[dev-dependencies] [dev-dependencies]
insta = { version = "1.40.0" } insta = { workspace = true }

View file

@ -4,6 +4,7 @@
mod error; mod error;
use std::borrow::Cow;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::fmt::Write; use std::fmt::Write;
@ -19,17 +20,20 @@ use fs_err as fs;
use indoc::formatdoc; use indoc::formatdoc;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use serde::de::{IntoDeserializer, SeqAccess, Visitor, value}; use serde::de::{self, IntoDeserializer, SeqAccess, Visitor, value};
use serde::{Deserialize, Deserializer, de}; use serde::{Deserialize, Deserializer};
use tempfile::TempDir; use tempfile::TempDir;
use tokio::io::AsyncBufReadExt; use tokio::io::AsyncBufReadExt;
use tokio::process::Command; use tokio::process::Command;
use tokio::sync::{Mutex, Semaphore}; use tokio::sync::{Mutex, Semaphore};
use tracing::{Instrument, debug, info_span, instrument}; use tracing::{Instrument, debug, info_span, instrument, warn};
use uv_cache_key::cache_digest;
use uv_configuration::Preview;
use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy}; use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy};
use uv_distribution::BuildRequires; use uv_distribution::BuildRequires;
use uv_distribution_types::{IndexLocations, Requirement, Resolution}; use uv_distribution_types::{IndexLocations, Requirement, Resolution};
use uv_fs::LockedFile;
use uv_fs::{PythonExt, Simplified}; use uv_fs::{PythonExt, Simplified};
use uv_pep440::Version; use uv_pep440::Version;
use uv_pep508::PackageName; use uv_pep508::PackageName;
@ -39,6 +43,7 @@ use uv_static::EnvVars;
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait};
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use uv_workspace::WorkspaceCache; use uv_workspace::WorkspaceCache;
use uv_workspace::pyproject::ExtraBuildDependencies;
pub use crate::error::{Error, MissingHeaderCause}; pub use crate::error::{Error, MissingHeaderCause};
@ -200,6 +205,11 @@ impl Pep517Backend {
{import} {import}
"#, backend_path = backend_path_encoded} "#, backend_path = backend_path_encoded}
} }
fn is_setuptools(&self) -> bool {
// either `setuptools.build_meta` or `setuptools.build_meta:__legacy__`
self.backend.split(':').next() == Some("setuptools.build_meta")
}
} }
/// Uses an [`Rc`] internally, clone freely. /// Uses an [`Rc`] internally, clone freely.
@ -273,11 +283,13 @@ impl SourceBuild {
workspace_cache: &WorkspaceCache, workspace_cache: &WorkspaceCache,
config_settings: ConfigSettings, config_settings: ConfigSettings,
build_isolation: BuildIsolation<'_>, build_isolation: BuildIsolation<'_>,
extra_build_dependencies: &ExtraBuildDependencies,
build_stack: &BuildStack, build_stack: &BuildStack,
build_kind: BuildKind, build_kind: BuildKind,
mut environment_variables: FxHashMap<OsString, OsString>, mut environment_variables: FxHashMap<OsString, OsString>,
level: BuildOutput, level: BuildOutput,
concurrent_builds: usize, concurrent_builds: usize,
preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let temp_dir = build_context.cache().venv_dir()?; let temp_dir = build_context.cache().venv_dir()?;
@ -288,7 +300,6 @@ impl SourceBuild {
}; };
let default_backend: Pep517Backend = DEFAULT_BACKEND.clone(); let default_backend: Pep517Backend = DEFAULT_BACKEND.clone();
// Check if we have a PEP 517 build backend. // Check if we have a PEP 517 build backend.
let (pep517_backend, project) = Self::extract_pep517_backend( let (pep517_backend, project) = Self::extract_pep517_backend(
&source_tree, &source_tree,
@ -313,6 +324,14 @@ impl SourceBuild {
.or(fallback_package_version) .or(fallback_package_version)
.cloned(); .cloned();
let extra_build_dependencies: Vec<Requirement> = package_name
.as_ref()
.and_then(|name| extra_build_dependencies.get(name).cloned())
.unwrap_or_default()
.into_iter()
.map(Requirement::from)
.collect();
// Create a virtual environment, or install into the shared environment if requested. // Create a virtual environment, or install into the shared environment if requested.
let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) { let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) {
venv.clone() venv.clone()
@ -322,9 +341,11 @@ impl SourceBuild {
interpreter.clone(), interpreter.clone(),
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
uv_virtualenv::OnExisting::Remove,
false, false,
false, false,
false, false,
preview,
)? )?
}; };
@ -333,11 +354,18 @@ impl SourceBuild {
if build_isolation.is_isolated(package_name.as_ref()) { if build_isolation.is_isolated(package_name.as_ref()) {
debug!("Resolving build requirements"); debug!("Resolving build requirements");
let dependency_sources = if extra_build_dependencies.is_empty() {
"`build-system.requires`"
} else {
"`build-system.requires` and `extra-build-dependencies`"
};
let resolved_requirements = Self::get_resolved_requirements( let resolved_requirements = Self::get_resolved_requirements(
build_context, build_context,
source_build_context, source_build_context,
&default_backend, &default_backend,
&pep517_backend, &pep517_backend,
extra_build_dependencies,
build_stack, build_stack,
) )
.await?; .await?;
@ -345,7 +373,7 @@ impl SourceBuild {
build_context build_context
.install(&resolved_requirements, &venv, build_stack) .install(&resolved_requirements, &venv, build_stack)
.await .await
.map_err(|err| Error::RequirementsInstall("`build-system.requires`", err.into()))?; .map_err(|err| Error::RequirementsInstall(dependency_sources, err.into()))?;
} else { } else {
debug!("Proceeding without build isolation"); debug!("Proceeding without build isolation");
} }
@ -430,15 +458,43 @@ impl SourceBuild {
}) })
} }
/// Acquire a lock on the source tree, if necessary.
async fn acquire_lock(&self) -> Result<Option<LockedFile>, Error> {
// Depending on the command, setuptools puts `*.egg-info`, `build/`, and `dist/` in the
// source tree, and concurrent invocations of setuptools using the same source dir can
// stomp on each other. We need to lock something to fix that, but we don't want to dump a
// `.lock` file into the source tree that the user will need to .gitignore. Take a global
// proxy lock instead.
let mut source_tree_lock = None;
if self.pep517_backend.is_setuptools() {
debug!("Locking the source tree for setuptools");
let canonical_source_path = self.source_tree.canonicalize()?;
let lock_path = env::temp_dir().join(format!(
"uv-setuptools-{}.lock",
cache_digest(&canonical_source_path)
));
source_tree_lock = LockedFile::acquire(lock_path, self.source_tree.to_string_lossy())
.await
.inspect_err(|err| {
warn!("Failed to acquire build lock: {err}");
})
.ok();
}
Ok(source_tree_lock)
}
async fn get_resolved_requirements( async fn get_resolved_requirements(
build_context: &impl BuildContext, build_context: &impl BuildContext,
source_build_context: SourceBuildContext, source_build_context: SourceBuildContext,
default_backend: &Pep517Backend, default_backend: &Pep517Backend,
pep517_backend: &Pep517Backend, pep517_backend: &Pep517Backend,
extra_build_dependencies: Vec<Requirement>,
build_stack: &BuildStack, build_stack: &BuildStack,
) -> Result<Resolution, Error> { ) -> Result<Resolution, Error> {
Ok( Ok(
if pep517_backend.requirements == default_backend.requirements { if pep517_backend.requirements == default_backend.requirements
&& extra_build_dependencies.is_empty()
{
let mut resolution = source_build_context.default_resolution.lock().await; let mut resolution = source_build_context.default_resolution.lock().await;
if let Some(resolved_requirements) = &*resolution { if let Some(resolved_requirements) = &*resolution {
resolved_requirements.clone() resolved_requirements.clone()
@ -453,12 +509,25 @@ impl SourceBuild {
resolved_requirements resolved_requirements
} }
} else { } else {
let (requirements, dependency_sources) = if extra_build_dependencies.is_empty() {
(
Cow::Borrowed(&pep517_backend.requirements),
"`build-system.requires`",
)
} else {
// If there are extra build dependencies, we need to resolve them together with
// the backend requirements.
let mut requirements = pep517_backend.requirements.clone();
requirements.extend(extra_build_dependencies);
(
Cow::Owned(requirements),
"`build-system.requires` and `extra-build-dependencies`",
)
};
build_context build_context
.resolve(&pep517_backend.requirements, build_stack) .resolve(&requirements, build_stack)
.await .await
.map_err(|err| { .map_err(|err| Error::RequirementsResolve(dependency_sources, err.into()))?
Error::RequirementsResolve("`build-system.requires`", err.into())
})?
}, },
) )
} }
@ -475,11 +544,9 @@ impl SourceBuild {
) -> Result<(Pep517Backend, Option<Project>), Box<Error>> { ) -> Result<(Pep517Backend, Option<Project>), Box<Error>> {
match fs::read_to_string(source_tree.join("pyproject.toml")) { match fs::read_to_string(source_tree.join("pyproject.toml")) {
Ok(toml) => { Ok(toml) => {
let pyproject_toml: toml_edit::ImDocument<_> = let pyproject_toml = toml_edit::Document::from_str(&toml)
toml_edit::ImDocument::from_str(&toml)
.map_err(Error::InvalidPyprojectTomlSyntax)?; .map_err(Error::InvalidPyprojectTomlSyntax)?;
let pyproject_toml: PyProjectToml = let pyproject_toml = PyProjectToml::deserialize(pyproject_toml.into_deserializer())
PyProjectToml::deserialize(pyproject_toml.into_deserializer())
.map_err(Error::InvalidPyprojectTomlSchema)?; .map_err(Error::InvalidPyprojectTomlSchema)?;
let backend = if let Some(build_system) = pyproject_toml.build_system { let backend = if let Some(build_system) = pyproject_toml.build_system {
@ -570,6 +637,7 @@ impl SourceBuild {
); );
} }
} }
default_backend.clone() default_backend.clone()
}; };
Ok((backend, pyproject_toml.project)) Ok((backend, pyproject_toml.project))
@ -600,6 +668,9 @@ impl SourceBuild {
return Ok(Some(metadata_dir.clone())); return Ok(Some(metadata_dir.clone()));
} }
// Lock the source tree, if necessary.
let _lock = self.acquire_lock().await?;
// Hatch allows for highly dynamic customization of metadata via hooks. In such cases, Hatch // Hatch allows for highly dynamic customization of metadata via hooks. In such cases, Hatch
// can't uphold the PEP 517 contract, in that the metadata Hatch would return by // can't uphold the PEP 517 contract, in that the metadata Hatch would return by
// `prepare_metadata_for_build_wheel` isn't guaranteed to match that of the built wheel. // `prepare_metadata_for_build_wheel` isn't guaranteed to match that of the built wheel.
@ -712,16 +783,15 @@ impl SourceBuild {
pub async fn build(&self, wheel_dir: &Path) -> Result<String, Error> { pub async fn build(&self, wheel_dir: &Path) -> Result<String, Error> {
// The build scripts run with the extracted root as cwd, so they need the absolute path. // The build scripts run with the extracted root as cwd, so they need the absolute path.
let wheel_dir = std::path::absolute(wheel_dir)?; let wheel_dir = std::path::absolute(wheel_dir)?;
let filename = self.pep517_build(&wheel_dir, &self.pep517_backend).await?; let filename = self.pep517_build(&wheel_dir).await?;
Ok(filename) Ok(filename)
} }
/// Perform a PEP 517 build for a wheel or source distribution (sdist). /// Perform a PEP 517 build for a wheel or source distribution (sdist).
async fn pep517_build( async fn pep517_build(&self, output_dir: &Path) -> Result<String, Error> {
&self, // Lock the source tree, if necessary.
output_dir: &Path, let _lock = self.acquire_lock().await?;
pep517_backend: &Pep517Backend,
) -> Result<String, Error> {
// Write the hook output to a file so that we can read it back reliably. // Write the hook output to a file so that we can read it back reliably.
let outfile = self let outfile = self
.temp_dir .temp_dir
@ -733,7 +803,7 @@ impl SourceBuild {
BuildKind::Sdist => { BuildKind::Sdist => {
debug!( debug!(
r#"Calling `{}.build_{}("{}", {})`"#, r#"Calling `{}.build_{}("{}", {})`"#,
pep517_backend.backend, self.pep517_backend.backend,
self.build_kind, self.build_kind,
output_dir.escape_for_python(), output_dir.escape_for_python(),
self.config_settings.escape_for_python(), self.config_settings.escape_for_python(),
@ -746,7 +816,7 @@ impl SourceBuild {
with open("{}", "w") as fp: with open("{}", "w") as fp:
fp.write(sdist_filename) fp.write(sdist_filename)
"#, "#,
pep517_backend.backend_import(), self.pep517_backend.backend_import(),
self.build_kind, self.build_kind,
output_dir.escape_for_python(), output_dir.escape_for_python(),
self.config_settings.escape_for_python(), self.config_settings.escape_for_python(),
@ -762,7 +832,7 @@ impl SourceBuild {
}); });
debug!( debug!(
r#"Calling `{}.build_{}("{}", {}, {})`"#, r#"Calling `{}.build_{}("{}", {}, {})`"#,
pep517_backend.backend, self.pep517_backend.backend,
self.build_kind, self.build_kind,
output_dir.escape_for_python(), output_dir.escape_for_python(),
self.config_settings.escape_for_python(), self.config_settings.escape_for_python(),
@ -776,7 +846,7 @@ impl SourceBuild {
with open("{}", "w") as fp: with open("{}", "w") as fp:
fp.write(wheel_filename) fp.write(wheel_filename)
"#, "#,
pep517_backend.backend_import(), self.pep517_backend.backend_import(),
self.build_kind, self.build_kind,
output_dir.escape_for_python(), output_dir.escape_for_python(),
self.config_settings.escape_for_python(), self.config_settings.escape_for_python(),
@ -806,7 +876,7 @@ impl SourceBuild {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Call to `{}.build_{}` failed", "Call to `{}.build_{}` failed",
pep517_backend.backend, self.build_kind self.pep517_backend.backend, self.build_kind
), ),
&output, &output,
self.level, self.level,
@ -821,7 +891,7 @@ impl SourceBuild {
return Err(Error::from_command_output( return Err(Error::from_command_output(
format!( format!(
"Call to `{}.build_{}` failed", "Call to `{}.build_{}` failed",
pep517_backend.backend, self.build_kind self.pep517_backend.backend, self.build_kind
), ),
&output, &output,
self.level, self.level,

View file

@ -1,13 +1,13 @@
[package] [package]
name = "uv-build" name = "uv-build"
version = "0.7.6" version = "0.8.4"
edition.workspace = true edition = { workspace = true }
rust-version.workspace = true rust-version = { workspace = true }
homepage.workspace = true homepage = { workspace = true }
documentation.workspace = true documentation = { workspace = true }
repository.workspace = true repository = { workspace = true }
authors.workspace = true authors = { workspace = true }
license.workspace = true license = { workspace = true }
[dependencies] [dependencies]
uv-build-backend = { workspace = true } uv-build-backend = { workspace = true }

View file

@ -1,6 +1,6 @@
[project] [project]
name = "uv-build" name = "uv-build"
version = "0.7.6" version = "0.8.4"
description = "The uv build backend" description = "The uv build backend"
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
requires-python = ">=3.8" requires-python = ">=3.8"

View file

@ -0,0 +1,2 @@
# It is important retain compatibility with old versions in the build backend
target-version = "py37"

View file

@ -24,3 +24,7 @@ thiserror = { workspace = true }
toml = { workspace = true } toml = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
walkdir = { workspace = true } walkdir = { workspace = true }
[dev-dependencies]
anyhow = { workspace = true }
tempfile = { workspace = true }

View file

@ -7,6 +7,7 @@ use serde::Deserialize;
use tracing::{debug, warn}; use tracing::{debug, warn};
use crate::git_info::{Commit, Tags}; use crate::git_info::{Commit, Tags};
use crate::glob::cluster_globs;
use crate::timestamp::Timestamp; use crate::timestamp::Timestamp;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -212,9 +213,13 @@ impl CacheInfo {
} }
} }
// If we have any globs, process them in a single pass. // If we have any globs, first cluster them using LCP and then do a single pass on each group.
if !globs.is_empty() { if !globs.is_empty() {
let walker = globwalk::GlobWalkerBuilder::from_patterns(directory, &globs) for (glob_base, glob_patterns) in cluster_globs(&globs) {
let walker = globwalk::GlobWalkerBuilder::from_patterns(
directory.join(glob_base),
&glob_patterns,
)
.file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK) .file_type(globwalk::FileType::FILE | globwalk::FileType::SYMLINK)
.build()?; .build()?;
for entry in walker { for entry in walker {
@ -225,23 +230,38 @@ impl CacheInfo {
continue; continue;
} }
}; };
let metadata = match entry.metadata() { let metadata = if entry.path_is_symlink() {
// resolve symlinks for leaf entries without following symlinks while globbing
match fs_err::metadata(entry.path()) {
Ok(metadata) => metadata,
Err(err) => {
warn!("Failed to resolve symlink for glob entry: {err}");
continue;
}
}
} else {
match entry.metadata() {
Ok(metadata) => metadata, Ok(metadata) => metadata,
Err(err) => { Err(err) => {
warn!("Failed to read metadata for glob entry: {err}"); warn!("Failed to read metadata for glob entry: {err}");
continue; continue;
} }
}
}; };
if !metadata.is_file() { if !metadata.is_file() {
if !entry.path_is_symlink() {
// don't warn if it was a symlink - it may legitimately resolve to a directory
warn!( warn!(
"Expected file for cache key, but found directory: `{}`", "Expected file for cache key, but found directory: `{}`",
entry.path().display() entry.path().display()
); );
}
continue; continue;
} }
timestamp = max(timestamp, Some(Timestamp::from_metadata(&metadata))); timestamp = max(timestamp, Some(Timestamp::from_metadata(&metadata)));
} }
} }
}
debug!( debug!(
"Computed cache info: {timestamp:?}, {commit:?}, {tags:?}, {env:?}, {directories:?}" "Computed cache info: {timestamp:?}, {commit:?}, {tags:?}, {env:?}, {directories:?}"
@ -340,3 +360,71 @@ enum DirectoryTimestamp {
Timestamp(Timestamp), Timestamp(Timestamp),
Inode(u64), Inode(u64),
} }
#[cfg(all(test, unix))]
mod tests_unix {
use anyhow::Result;
use super::{CacheInfo, Timestamp};
#[test]
fn test_cache_info_symlink_resolve() -> Result<()> {
let dir = tempfile::tempdir()?;
let dir = dir.path().join("dir");
fs_err::create_dir_all(&dir)?;
let write_manifest = |cache_key: &str| {
fs_err::write(
dir.join("pyproject.toml"),
format!(
r#"
[tool.uv]
cache-keys = [
"{cache_key}"
]
"#
),
)
};
let touch = |path: &str| -> Result<_> {
let path = dir.join(path);
fs_err::create_dir_all(path.parent().unwrap())?;
fs_err::write(&path, "")?;
Ok(Timestamp::from_metadata(&path.metadata()?))
};
let cache_timestamp = || -> Result<_> { Ok(CacheInfo::from_directory(&dir)?.timestamp) };
write_manifest("x/**")?;
assert_eq!(cache_timestamp()?, None);
let y = touch("x/y")?;
assert_eq!(cache_timestamp()?, Some(y));
let z = touch("x/z")?;
assert_eq!(cache_timestamp()?, Some(z));
// leaf entry symlink should be resolved
let a = touch("../a")?;
fs_err::os::unix::fs::symlink(dir.join("../a"), dir.join("x/a"))?;
assert_eq!(cache_timestamp()?, Some(a));
// symlink directories should not be followed while globbing
let c = touch("../b/c")?;
fs_err::os::unix::fs::symlink(dir.join("../b"), dir.join("x/b"))?;
assert_eq!(cache_timestamp()?, Some(a));
// no globs, should work as expected
write_manifest("x/y")?;
assert_eq!(cache_timestamp()?, Some(y));
write_manifest("x/a")?;
assert_eq!(cache_timestamp()?, Some(a));
write_manifest("x/b/c")?;
assert_eq!(cache_timestamp()?, Some(c));
// symlink pointing to a directory
write_manifest("x/*b*")?;
assert_eq!(cache_timestamp()?, None);
Ok(())
}
}

View file

@ -0,0 +1,318 @@
use std::{
collections::BTreeMap,
path::{Component, Components, Path, PathBuf},
};
/// Check if a component of the path looks like it may be a glob pattern.
///
/// Note: this function is being used when splitting a glob pattern into a long possible
/// base and the glob remainder (scanning through components until we hit the first component
/// for which this function returns true). It is acceptable for this function to return
/// false positives (e.g. patterns like 'foo[bar' or 'foo{bar') in which case correctness
/// will not be affected but efficiency might be (because we'll traverse more than we should),
/// however it should not return false negatives.
fn is_glob_like(part: Component) -> bool {
matches!(part, Component::Normal(_))
&& part.as_os_str().to_str().is_some_and(|part| {
["*", "{", "}", "?", "[", "]"]
.into_iter()
.any(|c| part.contains(c))
})
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
struct GlobParts {
base: PathBuf,
pattern: PathBuf,
}
/// Split a glob into longest possible base + shortest possible glob pattern.
fn split_glob(pattern: impl AsRef<str>) -> GlobParts {
let pattern: &Path = pattern.as_ref().as_ref();
let mut glob = GlobParts::default();
let mut globbing = false;
let mut last = None;
for part in pattern.components() {
if let Some(last) = last {
if last != Component::CurDir {
if globbing {
glob.pattern.push(last);
} else {
glob.base.push(last);
}
}
}
if !globbing {
globbing = is_glob_like(part);
}
// we don't know if this part is the last one, defer handling it by one iteration
last = Some(part);
}
if let Some(last) = last {
// defer handling the last component to prevent draining entire pattern into base
if globbing || matches!(last, Component::Normal(_)) {
glob.pattern.push(last);
} else {
glob.base.push(last);
}
}
glob
}
/// Classic trie with edges being path components and values being glob patterns.
#[derive(Default)]
struct Trie<'a> {
children: BTreeMap<Component<'a>, Trie<'a>>,
patterns: Vec<&'a Path>,
}
impl<'a> Trie<'a> {
fn insert(&mut self, mut components: Components<'a>, pattern: &'a Path) {
if let Some(part) = components.next() {
self.children
.entry(part)
.or_default()
.insert(components, pattern);
} else {
self.patterns.push(pattern);
}
}
#[allow(clippy::needless_pass_by_value)]
fn collect_patterns(
&self,
pattern_prefix: PathBuf,
group_prefix: PathBuf,
patterns: &mut Vec<PathBuf>,
groups: &mut Vec<(PathBuf, Vec<PathBuf>)>,
) {
// collect all patterns beneath and including this node
for pattern in &self.patterns {
patterns.push(pattern_prefix.join(pattern));
}
for (part, child) in &self.children {
if let Component::Normal(_) = part {
// for normal components, collect all descendant patterns ('normal' edges only)
child.collect_patterns(
pattern_prefix.join(part),
group_prefix.join(part),
patterns,
groups,
);
} else {
// for non-normal component edges, kick off separate group collection at this node
child.collect_groups(group_prefix.join(part), groups);
}
}
}
#[allow(clippy::needless_pass_by_value)]
fn collect_groups(&self, prefix: PathBuf, groups: &mut Vec<(PathBuf, Vec<PathBuf>)>) {
// LCP-style grouping of patterns
if self.patterns.is_empty() {
// no patterns in this node; child nodes can form independent groups
for (part, child) in &self.children {
child.collect_groups(prefix.join(part), groups);
}
} else {
// pivot point, we've hit a pattern node; we have to stop here and form a group
let mut group = Vec::new();
self.collect_patterns(PathBuf::new(), prefix.clone(), &mut group, groups);
groups.push((prefix, group));
}
}
}
/// Given a collection of globs, cluster them into (base, globs) groups so that:
/// - base doesn't contain any glob symbols
/// - each directory would only be walked at most once
/// - base of each group is the longest common prefix of globs in the group
pub(crate) fn cluster_globs(patterns: &[impl AsRef<str>]) -> Vec<(PathBuf, Vec<String>)> {
// split all globs into base/pattern
let globs: Vec<_> = patterns.iter().map(split_glob).collect();
// construct a path trie out of all split globs
let mut trie = Trie::default();
for glob in &globs {
trie.insert(glob.base.components(), &glob.pattern);
}
// run LCP-style aggregation of patterns in the trie into groups
let mut groups = Vec::new();
trie.collect_groups(PathBuf::new(), &mut groups);
// finally, convert resulting patterns to strings
groups
.into_iter()
.map(|(base, patterns)| {
(
base,
patterns
.iter()
// NOTE: this unwrap is ok because input patterns are valid utf-8
.map(|p| p.to_str().unwrap().to_owned())
.collect(),
)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::{GlobParts, cluster_globs, split_glob};
fn windowsify(path: &str) -> String {
if cfg!(windows) {
path.replace('/', "\\")
} else {
path.to_owned()
}
}
#[test]
fn test_split_glob() {
#[track_caller]
fn check(input: &str, base: &str, pattern: &str) {
let result = split_glob(input);
let expected = GlobParts {
base: base.into(),
pattern: pattern.into(),
};
assert_eq!(result, expected, "{input:?} != {base:?} + {pattern:?}");
}
check("", "", "");
check("a", "", "a");
check("a/b", "a", "b");
check("a/b/", "a", "b");
check("a/.//b/", "a", "b");
check("./a/b/c", "a/b", "c");
check("c/d/*", "c/d", "*");
check("c/d/*/../*", "c/d", "*/../*");
check("a/?b/c", "a", "?b/c");
check("/a/b/*", "/a/b", "*");
check("../x/*", "../x", "*");
check("a/{b,c}/d", "a", "{b,c}/d");
check("a/[bc]/d", "a", "[bc]/d");
check("*", "", "*");
check("*/*", "", "*/*");
check("..", "..", "");
check("/", "/", "");
}
#[test]
fn test_cluster_globs() {
#[track_caller]
fn check(input: &[&str], expected: &[(&str, &[&str])]) {
let input = input.iter().map(|s| windowsify(s)).collect::<Vec<_>>();
let mut result_sorted = cluster_globs(&input);
for (_, patterns) in &mut result_sorted {
patterns.sort_unstable();
}
result_sorted.sort_unstable();
let mut expected_sorted = Vec::new();
for (base, patterns) in expected {
let mut patterns_sorted = Vec::new();
for pattern in *patterns {
patterns_sorted.push(windowsify(pattern));
}
patterns_sorted.sort_unstable();
expected_sorted.push((windowsify(base).into(), patterns_sorted));
}
expected_sorted.sort_unstable();
assert_eq!(
result_sorted, expected_sorted,
"{input:?} != {expected_sorted:?} (got: {result_sorted:?})"
);
}
check(&["a/b/*", "a/c/*"], &[("a/b", &["*"]), ("a/c", &["*"])]);
check(&["./a/b/*", "a/c/*"], &[("a/b", &["*"]), ("a/c", &["*"])]);
check(&["/a/b/*", "/a/c/*"], &[("/a/b", &["*"]), ("/a/c", &["*"])]);
check(
&["../a/b/*", "../a/c/*"],
&[("../a/b", &["*"]), ("../a/c", &["*"])],
);
check(&["x/*", "y/*"], &[("x", &["*"]), ("y", &["*"])]);
check(&[], &[]);
check(
&["./*", "a/*", "../foo/*.png"],
&[("", &["*", "a/*"]), ("../foo", &["*.png"])],
);
check(
&[
"?",
"/foo/?",
"/foo/bar/*",
"../bar/*.png",
"../bar/../baz/*.jpg",
],
&[
("", &["?"]),
("/foo", &["?", "bar/*"]),
("../bar", &["*.png"]),
("../bar/../baz", &["*.jpg"]),
],
);
check(&["/abs/path/*"], &[("/abs/path", &["*"])]);
check(&["/abs/*", "rel/*"], &[("/abs", &["*"]), ("rel", &["*"])]);
check(&["a/{b,c}/*", "a/d?/*"], &[("a", &["{b,c}/*", "d?/*"])]);
check(
&[
"../shared/a/[abc].png",
"../shared/a/b/*",
"../shared/b/c/?x/d",
"docs/important/*.{doc,xls}",
"docs/important/very/*",
],
&[
("../shared/a", &["[abc].png", "b/*"]),
("../shared/b/c", &["?x/d"]),
("docs/important", &["*.{doc,xls}", "very/*"]),
],
);
check(&["file.txt"], &[("", &["file.txt"])]);
check(&["/"], &[("/", &[""])]);
check(&[".."], &[("..", &[""])]);
check(
&["file1.txt", "file2.txt"],
&[("", &["file1.txt", "file2.txt"])],
);
check(
&["a/file1.txt", "a/file2.txt"],
&[("a", &["file1.txt", "file2.txt"])],
);
check(
&["*", "a/b/*", "a/../c/*.jpg", "a/../c/*.png", "/a/*", "/b/*"],
&[
("", &["*", "a/b/*"]),
("a/../c", &["*.jpg", "*.png"]),
("/a", &["*"]),
("/b", &["*"]),
],
);
if cfg!(windows) {
check(
&[
r"\\foo\bar\shared/a/[abc].png",
r"\\foo\bar\shared/a/b/*",
r"\\foo\bar/shared/b/c/?x/d",
r"D:\docs\important/*.{doc,xls}",
r"D:\docs/important/very/*",
],
&[
(r"\\foo\bar\shared\a", &["[abc].png", r"b\*"]),
(r"\\foo\bar\shared\b\c", &[r"?x\d"]),
(r"D:\docs\important", &["*.{doc,xls}", r"very\*"]),
],
);
}
}
}

View file

@ -3,4 +3,5 @@ pub use crate::timestamp::*;
mod cache_info; mod cache_info;
mod git_info; mod git_info;
mod glob;
mod timestamp; mod timestamp;

View file

@ -17,6 +17,8 @@ doctest = false
workspace = true workspace = true
[dependencies] [dependencies]
uv-redacted = { workspace = true }
hex = { workspace = true } hex = { workspace = true }
memchr = { workspace = true } memchr = { workspace = true }
percent-encoding = { workspace = true } percent-encoding = { workspace = true }

View file

@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher};
use std::ops::Deref; use std::ops::Deref;
use url::Url; use url::Url;
use uv_redacted::DisplaySafeUrl;
use crate::cache_key::{CacheKey, CacheKeyHasher}; use crate::cache_key::{CacheKey, CacheKeyHasher};
@ -16,10 +17,10 @@ use crate::cache_key::{CacheKey, CacheKeyHasher};
/// string value of the `Url` it contains. This is intentional, because all fetching should still /// string value of the `Url` it contains. This is intentional, because all fetching should still
/// happen within the context of the original URL. /// happen within the context of the original URL.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct CanonicalUrl(Url); pub struct CanonicalUrl(DisplaySafeUrl);
impl CanonicalUrl { impl CanonicalUrl {
pub fn new(url: &Url) -> Self { pub fn new(url: &DisplaySafeUrl) -> Self {
let mut url = url.clone(); let mut url = url.clone();
// If the URL cannot be a base, then it's not a valid URL anyway. // If the URL cannot be a base, then it's not a valid URL anyway.
@ -42,8 +43,8 @@ impl CanonicalUrl {
// almost certainly not using the same case conversion rules that GitHub // almost certainly not using the same case conversion rules that GitHub
// does. (See issue #84) // does. (See issue #84)
if url.host_str() == Some("github.com") { if url.host_str() == Some("github.com") {
url.set_scheme(url.scheme().to_lowercase().as_str()) let scheme = url.scheme().to_lowercase();
.unwrap(); url.set_scheme(&scheme).unwrap();
let path = url.path().to_lowercase(); let path = url.path().to_lowercase();
url.set_path(&path); url.set_path(&path);
} }
@ -56,7 +57,8 @@ impl CanonicalUrl {
.is_some_and(|ext| ext.eq_ignore_ascii_case("git")); .is_some_and(|ext| ext.eq_ignore_ascii_case("git"));
if needs_chopping { if needs_chopping {
let prefix = &prefix[..prefix.len() - 4]; let prefix = &prefix[..prefix.len() - 4];
url.set_path(&format!("{prefix}@{suffix}")); let path = format!("{prefix}@{suffix}");
url.set_path(&path);
} }
} else { } else {
// Ex) `git+https://github.com/pypa/sample-namespace-packages.git` // Ex) `git+https://github.com/pypa/sample-namespace-packages.git`
@ -97,7 +99,7 @@ impl CanonicalUrl {
} }
pub fn parse(url: &str) -> Result<Self, url::ParseError> { pub fn parse(url: &str) -> Result<Self, url::ParseError> {
Ok(Self::new(&Url::parse(url)?)) Ok(Self::new(&DisplaySafeUrl::parse(url)?))
} }
} }
@ -117,7 +119,7 @@ impl Hash for CanonicalUrl {
} }
} }
impl From<CanonicalUrl> for Url { impl From<CanonicalUrl> for DisplaySafeUrl {
fn from(value: CanonicalUrl) -> Self { fn from(value: CanonicalUrl) -> Self {
value.0 value.0
} }
@ -138,10 +140,10 @@ impl std::fmt::Display for CanonicalUrl {
/// [`CanonicalUrl`] values, but the same [`RepositoryUrl`], since they map to the same /// [`CanonicalUrl`] values, but the same [`RepositoryUrl`], since they map to the same
/// resource. /// resource.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct RepositoryUrl(Url); pub struct RepositoryUrl(DisplaySafeUrl);
impl RepositoryUrl { impl RepositoryUrl {
pub fn new(url: &Url) -> Self { pub fn new(url: &DisplaySafeUrl) -> Self {
let mut url = CanonicalUrl::new(url).0; let mut url = CanonicalUrl::new(url).0;
// If a Git URL ends in a reference (like a branch, tag, or commit), remove it. // If a Git URL ends in a reference (like a branch, tag, or commit), remove it.
@ -163,7 +165,7 @@ impl RepositoryUrl {
} }
pub fn parse(url: &str) -> Result<Self, url::ParseError> { pub fn parse(url: &str) -> Result<Self, url::ParseError> {
Ok(Self::new(&Url::parse(url)?)) Ok(Self::new(&DisplaySafeUrl::parse(url)?))
} }
} }

View file

@ -24,6 +24,7 @@ uv-distribution-types = { workspace = true }
uv-fs = { workspace = true, features = ["tokio"] } uv-fs = { workspace = true, features = ["tokio"] }
uv-normalize = { workspace = true } uv-normalize = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-redacted = { workspace = true }
uv-static = { workspace = true } uv-static = { workspace = true }
clap = { workspace = true, features = ["derive", "env"], optional = true } clap = { workspace = true, features = ["derive", "env"], optional = true }
@ -35,5 +36,4 @@ same-file = { workspace = true }
serde = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] }
tempfile = { workspace = true } tempfile = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
url = { workspace = true }
walkdir = { workspace = true } walkdir = { workspace = true }

View file

@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use rustc_hash::FxHashSet; use rustc_hash::FxHashMap;
use tracing::debug; use tracing::debug;
pub use archive::ArchiveId; pub use archive::ArchiveId;
@ -375,7 +375,7 @@ impl Cache {
/// Returns the number of entries removed from the cache. /// Returns the number of entries removed from the cache.
pub fn remove(&self, name: &PackageName) -> Result<Removal, io::Error> { pub fn remove(&self, name: &PackageName) -> Result<Removal, io::Error> {
// Collect the set of referenced archives. // Collect the set of referenced archives.
let before = self.find_archive_references()?; let references = self.find_archive_references()?;
// Remove any entries for the package from the cache. // Remove any entries for the package from the cache.
let mut summary = Removal::default(); let mut summary = Removal::default();
@ -383,18 +383,11 @@ impl Cache {
summary += bucket.remove(self, name)?; summary += bucket.remove(self, name)?;
} }
// Collect the set of referenced archives after the removal.
let after = self.find_archive_references()?;
if before != after {
// Remove any archives that are no longer referenced. // Remove any archives that are no longer referenced.
for entry in fs_err::read_dir(self.bucket(CacheBucket::Archive))? { for (target, references) in references {
let entry = entry?; if references.iter().all(|path| !path.exists()) {
let path = fs_err::canonicalize(entry.path())?; debug!("Removing dangling cache entry: {}", target.display());
if !after.contains(&path) && before.contains(&path) { summary += rm_rf(target)?;
debug!("Removing dangling cache entry: {}", path.display());
summary += rm_rf(path)?;
}
} }
} }
@ -513,7 +506,7 @@ impl Cache {
for entry in entries { for entry in entries {
let entry = entry?; let entry = entry?;
let path = fs_err::canonicalize(entry.path())?; let path = fs_err::canonicalize(entry.path())?;
if !references.contains(&path) { if !references.contains_key(&path) {
debug!("Removing dangling cache archive: {}", path.display()); debug!("Removing dangling cache archive: {}", path.display());
summary += rm_rf(path)?; summary += rm_rf(path)?;
} }
@ -530,33 +523,52 @@ impl Cache {
/// ///
/// Archive entries are often referenced by symlinks in other cache buckets. This method /// Archive entries are often referenced by symlinks in other cache buckets. This method
/// searches for all such references. /// searches for all such references.
fn find_archive_references(&self) -> Result<FxHashSet<PathBuf>, io::Error> { ///
let mut references = FxHashSet::default(); /// Returns a map from archive path to paths that reference it.
for bucket in CacheBucket::iter() { fn find_archive_references(&self) -> Result<FxHashMap<PathBuf, Vec<PathBuf>>, io::Error> {
// As an optimization, skip the archive bucket itself. let mut references = FxHashMap::<PathBuf, Vec<PathBuf>>::default();
if matches!(bucket, CacheBucket::Archive) { for bucket in [CacheBucket::SourceDistributions, CacheBucket::Wheels] {
continue;
}
let bucket_path = self.bucket(bucket); let bucket_path = self.bucket(bucket);
if bucket_path.is_dir() { if bucket_path.is_dir() {
for entry in walkdir::WalkDir::new(bucket_path) { let walker = walkdir::WalkDir::new(&bucket_path).into_iter();
let entry = entry?; for entry in walker.filter_entry(|entry| {
!(
// As an optimization, ignore any `.lock`, `.whl`, `.msgpack`, `.rev`, or // As an optimization, ignore any `.lock`, `.whl`, `.msgpack`, `.rev`, or
// `.http` files. // `.http` files, along with the `src` directory, which represents the
if entry.path().extension().is_some_and(|ext| { // unpacked source distribution.
entry.file_name() == "src"
|| entry.file_name() == ".lock"
|| entry.file_name() == ".gitignore"
|| entry.path().extension().is_some_and(|ext| {
ext.eq_ignore_ascii_case("lock") ext.eq_ignore_ascii_case("lock")
|| ext.eq_ignore_ascii_case("whl") || ext.eq_ignore_ascii_case("whl")
|| ext.eq_ignore_ascii_case("http") || ext.eq_ignore_ascii_case("http")
|| ext.eq_ignore_ascii_case("rev") || ext.eq_ignore_ascii_case("rev")
|| ext.eq_ignore_ascii_case("msgpack") || ext.eq_ignore_ascii_case("msgpack")
})
)
}) { }) {
let entry = entry?;
// On Unix, archive references use symlinks.
if cfg!(unix) {
if !entry.file_type().is_symlink() {
continue; continue;
} }
}
// On Windows, archive references are files containing structured data.
if cfg!(windows) {
if !entry.file_type().is_file() {
continue;
}
}
if let Ok(target) = self.resolve_link(entry.path()) { if let Ok(target) = self.resolve_link(entry.path()) {
references.insert(target); references
.entry(target)
.or_default()
.push(entry.path().to_path_buf());
} }
} }
} }
@ -973,6 +985,8 @@ pub enum CacheBucket {
Builds, Builds,
/// Reusable virtual environments used to invoke Python tools. /// Reusable virtual environments used to invoke Python tools.
Environments, Environments,
/// Cached Python downloads
Python,
} }
impl CacheBucket { impl CacheBucket {
@ -995,6 +1009,7 @@ impl CacheBucket {
Self::Archive => "archive-v0", Self::Archive => "archive-v0",
Self::Builds => "builds-v0", Self::Builds => "builds-v0",
Self::Environments => "environments-v2", Self::Environments => "environments-v2",
Self::Python => "python-v0",
} }
} }
@ -1096,7 +1111,12 @@ impl CacheBucket {
let root = cache.bucket(self); let root = cache.bucket(self);
summary += rm_rf(root)?; summary += rm_rf(root)?;
} }
Self::Git | Self::Interpreter | Self::Archive | Self::Builds | Self::Environments => { Self::Git
| Self::Interpreter
| Self::Archive
| Self::Builds
| Self::Environments
| Self::Python => {
// Nothing to do. // Nothing to do.
} }
} }

View file

@ -1,9 +1,8 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use url::Url;
use uv_cache_key::{CanonicalUrl, cache_digest}; use uv_cache_key::{CanonicalUrl, cache_digest};
use uv_distribution_types::IndexUrl; use uv_distribution_types::IndexUrl;
use uv_redacted::DisplaySafeUrl;
/// Cache wheels and their metadata, both from remote wheels and built from source distributions. /// Cache wheels and their metadata, both from remote wheels and built from source distributions.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -11,16 +10,16 @@ pub enum WheelCache<'a> {
/// Either PyPI or an alternative index, which we key by index URL. /// Either PyPI or an alternative index, which we key by index URL.
Index(&'a IndexUrl), Index(&'a IndexUrl),
/// A direct URL dependency, which we key by URL. /// A direct URL dependency, which we key by URL.
Url(&'a Url), Url(&'a DisplaySafeUrl),
/// A path dependency, which we key by URL. /// A path dependency, which we key by URL.
Path(&'a Url), Path(&'a DisplaySafeUrl),
/// An editable dependency, which we key by URL. /// An editable dependency, which we key by URL.
Editable(&'a Url), Editable(&'a DisplaySafeUrl),
/// A Git dependency, which we key by URL and SHA. /// A Git dependency, which we key by URL and SHA.
/// ///
/// Note that this variant only exists for source distributions; wheels can't be delivered /// Note that this variant only exists for source distributions; wheels can't be delivered
/// through Git. /// through Git.
Git(&'a Url, &'a str), Git(&'a DisplaySafeUrl, &'a str),
} }
impl WheelCache<'_> { impl WheelCache<'_> {
@ -30,7 +29,7 @@ impl WheelCache<'_> {
WheelCache::Index(IndexUrl::Pypi(_)) => WheelCacheKind::Pypi.root(), WheelCache::Index(IndexUrl::Pypi(_)) => WheelCacheKind::Pypi.root(),
WheelCache::Index(url) => WheelCacheKind::Index WheelCache::Index(url) => WheelCacheKind::Index
.root() .root()
.join(cache_digest(&CanonicalUrl::new(url))), .join(cache_digest(&CanonicalUrl::new(url.url()))),
WheelCache::Url(url) => WheelCacheKind::Url WheelCache::Url(url) => WheelCacheKind::Url
.root() .root()
.join(cache_digest(&CanonicalUrl::new(url))), .join(cache_digest(&CanonicalUrl::new(url))),

View file

@ -25,12 +25,14 @@ uv-normalize = { workspace = true }
uv-pep508 = { workspace = true } uv-pep508 = { workspace = true }
uv-pypi-types = { workspace = true } uv-pypi-types = { workspace = true }
uv-python = { workspace = true, features = ["clap", "schemars"]} uv-python = { workspace = true, features = ["clap", "schemars"]}
uv-redacted = { workspace = true }
uv-resolver = { workspace = true, features = ["clap"] } uv-resolver = { workspace = true, features = ["clap"] }
uv-settings = { workspace = true, features = ["schemars"] } uv-settings = { workspace = true, features = ["schemars"] }
uv-static = { workspace = true } uv-static = { workspace = true }
uv-torch = { workspace = true, features = ["clap"] } uv-torch = { workspace = true, features = ["clap"] }
uv-version = { workspace = true } uv-version = { workspace = true }
uv-warnings = { workspace = true } uv-warnings = { workspace = true }
uv-workspace = { workspace = true }
anstream = { workspace = true } anstream = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
@ -40,7 +42,7 @@ serde = { workspace = true }
url = { workspace = true } url = { workspace = true }
[dev-dependencies] [dev-dependencies]
insta = { version = "1.40.0", features = ["filters", "json"] } insta = { workspace = true }
[features] [features]
default = [] default = []

View file

@ -13,7 +13,6 @@ pub trait CompatArgs {
/// For example, users often pass `--allow-unsafe`, which is unnecessary with uv. But it's a /// For example, users often pass `--allow-unsafe`, which is unnecessary with uv. But it's a
/// nice user experience to warn, rather than fail, when users pass `--allow-unsafe`. /// nice user experience to warn, rather than fail, when users pass `--allow-unsafe`.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipCompileCompatArgs { pub struct PipCompileCompatArgs {
#[clap(long, hide = true)] #[clap(long, hide = true)]
allow_unsafe: bool, allow_unsafe: bool,
@ -159,7 +158,6 @@ impl CompatArgs for PipCompileCompatArgs {
/// ///
/// These represent a subset of the `pip list` interface that uv supports by default. /// These represent a subset of the `pip list` interface that uv supports by default.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipListCompatArgs { pub struct PipListCompatArgs {
#[clap(long, hide = true)] #[clap(long, hide = true)]
disable_pip_version_check: bool, disable_pip_version_check: bool,
@ -184,7 +182,6 @@ impl CompatArgs for PipListCompatArgs {
/// ///
/// These represent a subset of the `pip-sync` interface that uv supports by default. /// These represent a subset of the `pip-sync` interface that uv supports by default.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipSyncCompatArgs { pub struct PipSyncCompatArgs {
#[clap(short, long, hide = true)] #[clap(short, long, hide = true)]
ask: bool, ask: bool,
@ -268,11 +265,7 @@ enum Resolver {
/// ///
/// These represent a subset of the `virtualenv` interface that uv supports by default. /// These represent a subset of the `virtualenv` interface that uv supports by default.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct VenvCompatArgs { pub struct VenvCompatArgs {
#[clap(long, hide = true)]
clear: bool,
#[clap(long, hide = true)] #[clap(long, hide = true)]
no_seed: bool, no_seed: bool,
@ -293,12 +286,6 @@ impl CompatArgs for VenvCompatArgs {
/// behavior. If an argument is passed that does _not_ match uv's behavior, this method will /// behavior. If an argument is passed that does _not_ match uv's behavior, this method will
/// return an error. /// return an error.
fn validate(&self) -> Result<()> { fn validate(&self) -> Result<()> {
if self.clear {
warn_user!(
"virtualenv's `--clear` has no effect (uv always clears the virtual environment)"
);
}
if self.no_seed { if self.no_seed {
warn_user!( warn_user!(
"virtualenv's `--no-seed` has no effect (uv omits seed packages by default)" "virtualenv's `--no-seed` has no effect (uv omits seed packages by default)"
@ -327,7 +314,6 @@ impl CompatArgs for VenvCompatArgs {
/// ///
/// These represent a subset of the `pip install` interface that uv supports by default. /// These represent a subset of the `pip install` interface that uv supports by default.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipInstallCompatArgs { pub struct PipInstallCompatArgs {
#[clap(long, hide = true)] #[clap(long, hide = true)]
disable_pip_version_check: bool, disable_pip_version_check: bool,
@ -361,7 +347,6 @@ impl CompatArgs for PipInstallCompatArgs {
/// ///
/// These represent a subset of the `pip` interface that exists on all commands. /// These represent a subset of the `pip` interface that exists on all commands.
#[derive(Args)] #[derive(Args)]
#[allow(clippy::struct_excessive_bools)]
pub struct PipGlobalCompatArgs { pub struct PipGlobalCompatArgs {
#[clap(long, hide = true)] #[clap(long, hide = true)]
disable_pip_version_check: bool, disable_pip_version_check: bool,

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,10 @@
use anstream::eprintln;
use uv_cache::Refresh; use uv_cache::Refresh;
use uv_configuration::ConfigSettings; use uv_configuration::{ConfigSettings, PackageConfigSettings};
use uv_resolver::PrereleaseMode; use uv_resolver::{ExcludeNewer, ExcludeNewerPackage, PrereleaseMode};
use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions}; use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions};
use uv_warnings::owo_colors::OwoColorize;
use crate::{ use crate::{
BuildOptionsArgs, FetchArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs, BuildOptionsArgs, FetchArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
@ -9,12 +12,27 @@ use crate::{
}; };
/// Given a boolean flag pair (like `--upgrade` and `--no-upgrade`), resolve the value of the flag. /// Given a boolean flag pair (like `--upgrade` and `--no-upgrade`), resolve the value of the flag.
pub fn flag(yes: bool, no: bool) -> Option<bool> { pub fn flag(yes: bool, no: bool, name: &str) -> Option<bool> {
match (yes, no) { match (yes, no) {
(true, false) => Some(true), (true, false) => Some(true),
(false, true) => Some(false), (false, true) => Some(false),
(false, false) => None, (false, false) => None,
(..) => unreachable!("Clap should make this impossible"), (..) => {
eprintln!(
"{}{} `{}` and `{}` cannot be used together. \
Boolean flags on different levels are currently not supported \
(https://github.com/clap-rs/clap/issues/6049)",
"error".bold().red(),
":".bold(),
format!("--{name}").green(),
format!("--no-{name}").green(),
);
// No error forwarding since should eventually be solved on the clap side.
#[allow(clippy::exit)]
{
std::process::exit(2);
}
}
} }
} }
@ -26,7 +44,7 @@ impl From<RefreshArgs> for Refresh {
refresh_package, refresh_package,
} = value; } = value;
Self::from_args(flag(refresh, no_refresh), refresh_package) Self::from_args(flag(refresh, no_refresh, "no-refresh"), refresh_package)
} }
} }
@ -44,16 +62,18 @@ impl From<ResolverArgs> for PipOptions {
pre, pre,
fork_strategy, fork_strategy,
config_setting, config_setting,
config_settings_package,
no_build_isolation, no_build_isolation,
no_build_isolation_package, no_build_isolation_package,
build_isolation, build_isolation,
exclude_newer, exclude_newer,
link_mode, link_mode,
no_sources, no_sources,
exclude_newer_package,
} = args; } = args;
Self { Self {
upgrade: flag(upgrade, no_upgrade), upgrade: flag(upgrade, no_upgrade, "no-upgrade"),
upgrade_package: Some(upgrade_package), upgrade_package: Some(upgrade_package),
index_strategy, index_strategy,
keyring_provider, keyring_provider,
@ -66,9 +86,15 @@ impl From<ResolverArgs> for PipOptions {
}, },
config_settings: config_setting config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()), .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
no_build_isolation: flag(no_build_isolation, build_isolation), config_settings_package: config_settings_package.map(|config_settings| {
config_settings
.into_iter()
.collect::<PackageConfigSettings>()
}),
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
no_build_isolation_package: Some(no_build_isolation_package), no_build_isolation_package: Some(no_build_isolation_package),
exclude_newer, exclude_newer,
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
link_mode, link_mode,
no_sources: if no_sources { Some(true) } else { None }, no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args) ..PipOptions::from(index_args)
@ -86,6 +112,7 @@ impl From<InstallerArgs> for PipOptions {
index_strategy, index_strategy,
keyring_provider, keyring_provider,
config_setting, config_setting,
config_settings_package,
no_build_isolation, no_build_isolation,
build_isolation, build_isolation,
exclude_newer, exclude_newer,
@ -93,19 +120,26 @@ impl From<InstallerArgs> for PipOptions {
compile_bytecode, compile_bytecode,
no_compile_bytecode, no_compile_bytecode,
no_sources, no_sources,
exclude_newer_package,
} = args; } = args;
Self { Self {
reinstall: flag(reinstall, no_reinstall), reinstall: flag(reinstall, no_reinstall, "reinstall"),
reinstall_package: Some(reinstall_package), reinstall_package: Some(reinstall_package),
index_strategy, index_strategy,
keyring_provider, keyring_provider,
config_settings: config_setting config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()), .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
no_build_isolation: flag(no_build_isolation, build_isolation), config_settings_package: config_settings_package.map(|config_settings| {
config_settings
.into_iter()
.collect::<PackageConfigSettings>()
}),
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
exclude_newer, exclude_newer,
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
link_mode, link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode), compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
no_sources: if no_sources { Some(true) } else { None }, no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args) ..PipOptions::from(index_args)
} }
@ -129,6 +163,7 @@ impl From<ResolverInstallerArgs> for PipOptions {
pre, pre,
fork_strategy, fork_strategy,
config_setting, config_setting,
config_settings_package,
no_build_isolation, no_build_isolation,
no_build_isolation_package, no_build_isolation_package,
build_isolation, build_isolation,
@ -137,12 +172,13 @@ impl From<ResolverInstallerArgs> for PipOptions {
compile_bytecode, compile_bytecode,
no_compile_bytecode, no_compile_bytecode,
no_sources, no_sources,
exclude_newer_package,
} = args; } = args;
Self { Self {
upgrade: flag(upgrade, no_upgrade), upgrade: flag(upgrade, no_upgrade, "upgrade"),
upgrade_package: Some(upgrade_package), upgrade_package: Some(upgrade_package),
reinstall: flag(reinstall, no_reinstall), reinstall: flag(reinstall, no_reinstall, "reinstall"),
reinstall_package: Some(reinstall_package), reinstall_package: Some(reinstall_package),
index_strategy, index_strategy,
keyring_provider, keyring_provider,
@ -155,11 +191,17 @@ impl From<ResolverInstallerArgs> for PipOptions {
fork_strategy, fork_strategy,
config_settings: config_setting config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()), .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
no_build_isolation: flag(no_build_isolation, build_isolation), config_settings_package: config_settings_package.map(|config_settings| {
config_settings
.into_iter()
.collect::<PackageConfigSettings>()
}),
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
no_build_isolation_package: Some(no_build_isolation_package), no_build_isolation_package: Some(no_build_isolation_package),
exclude_newer, exclude_newer,
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
link_mode, link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode), compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
no_sources: if no_sources { Some(true) } else { None }, no_sources: if no_sources { Some(true) } else { None },
..PipOptions::from(index_args) ..PipOptions::from(index_args)
} }
@ -242,12 +284,14 @@ pub fn resolver_options(
pre, pre,
fork_strategy, fork_strategy,
config_setting, config_setting,
config_settings_package,
no_build_isolation, no_build_isolation,
no_build_isolation_package, no_build_isolation_package,
build_isolation, build_isolation,
exclude_newer, exclude_newer,
link_mode, link_mode,
no_sources, no_sources,
exclude_newer_package,
} = resolver_args; } = resolver_args;
let BuildOptionsArgs { let BuildOptionsArgs {
@ -289,7 +333,7 @@ pub fn resolver_options(
.filter_map(Maybe::into_option) .filter_map(Maybe::into_option)
.collect() .collect()
}), }),
upgrade: flag(upgrade, no_upgrade), upgrade: flag(upgrade, no_upgrade, "no-upgrade"),
upgrade_package: Some(upgrade_package), upgrade_package: Some(upgrade_package),
index_strategy, index_strategy,
keyring_provider, keyring_provider,
@ -303,13 +347,22 @@ pub fn resolver_options(
dependency_metadata: None, dependency_metadata: None,
config_settings: config_setting config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()), .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
no_build_isolation: flag(no_build_isolation, build_isolation), config_settings_package: config_settings_package.map(|config_settings| {
config_settings
.into_iter()
.collect::<PackageConfigSettings>()
}),
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
no_build_isolation_package: Some(no_build_isolation_package), no_build_isolation_package: Some(no_build_isolation_package),
extra_build_dependencies: None,
exclude_newer: ExcludeNewer::from_args(
exclude_newer, exclude_newer,
exclude_newer_package.unwrap_or_default(),
),
link_mode, link_mode,
no_build: flag(no_build, build), no_build: flag(no_build, build, "build"),
no_build_package: Some(no_build_package), no_build_package: Some(no_build_package),
no_binary: flag(no_binary, binary), no_binary: flag(no_binary, binary, "binary"),
no_binary_package: Some(no_binary_package), no_binary_package: Some(no_binary_package),
no_sources: if no_sources { Some(true) } else { None }, no_sources: if no_sources { Some(true) } else { None },
} }
@ -335,10 +388,12 @@ pub fn resolver_installer_options(
pre, pre,
fork_strategy, fork_strategy,
config_setting, config_setting,
config_settings_package,
no_build_isolation, no_build_isolation,
no_build_isolation_package, no_build_isolation_package,
build_isolation, build_isolation,
exclude_newer, exclude_newer,
exclude_newer_package,
link_mode, link_mode,
compile_bytecode, compile_bytecode,
no_compile_bytecode, no_compile_bytecode,
@ -386,13 +441,13 @@ pub fn resolver_installer_options(
.filter_map(Maybe::into_option) .filter_map(Maybe::into_option)
.collect() .collect()
}), }),
upgrade: flag(upgrade, no_upgrade), upgrade: flag(upgrade, no_upgrade, "upgrade"),
upgrade_package: if upgrade_package.is_empty() { upgrade_package: if upgrade_package.is_empty() {
None None
} else { } else {
Some(upgrade_package) Some(upgrade_package)
}, },
reinstall: flag(reinstall, no_reinstall), reinstall: flag(reinstall, no_reinstall, "reinstall"),
reinstall_package: if reinstall_package.is_empty() { reinstall_package: if reinstall_package.is_empty() {
None None
} else { } else {
@ -410,22 +465,29 @@ pub fn resolver_installer_options(
dependency_metadata: None, dependency_metadata: None,
config_settings: config_setting config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()), .map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
no_build_isolation: flag(no_build_isolation, build_isolation), config_settings_package: config_settings_package.map(|config_settings| {
config_settings
.into_iter()
.collect::<PackageConfigSettings>()
}),
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
no_build_isolation_package: if no_build_isolation_package.is_empty() { no_build_isolation_package: if no_build_isolation_package.is_empty() {
None None
} else { } else {
Some(no_build_isolation_package) Some(no_build_isolation_package)
}, },
extra_build_dependencies: None,
exclude_newer, exclude_newer,
exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
link_mode, link_mode,
compile_bytecode: flag(compile_bytecode, no_compile_bytecode), compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
no_build: flag(no_build, build), no_build: flag(no_build, build, "build"),
no_build_package: if no_build_package.is_empty() { no_build_package: if no_build_package.is_empty() {
None None
} else { } else {
Some(no_build_package) Some(no_build_package)
}, },
no_binary: flag(no_binary, binary), no_binary: flag(no_binary, binary, "binary"),
no_binary_package: if no_binary_package.is_empty() { no_binary_package: if no_binary_package.is_empty() {
None None
} else { } else {

View file

@ -60,8 +60,9 @@ url = { workspace = true }
[dev-dependencies] [dev-dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
http-body-util = { version = "0.1.2" } http-body-util = { workspace = true }
hyper = { version = "1.4.1", features = ["server", "http1"] } hyper = { workspace = true }
hyper-util = { version = "0.1.8", features = ["tokio"] } hyper-util = { workspace = true }
insta = { version = "1.40.0", features = ["filters", "json", "redactions"] } insta = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
wiremock = { workspace = true }

View file

@ -6,21 +6,33 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::{env, io, iter}; use std::{env, io, iter};
use anyhow::Context;
use anyhow::anyhow;
use http::{
HeaderMap, HeaderName, HeaderValue, Method, StatusCode,
header::{
AUTHORIZATION, CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TYPE, COOKIE, LOCATION,
PROXY_AUTHORIZATION, REFERER, TRANSFER_ENCODING, WWW_AUTHENTICATE,
},
};
use itertools::Itertools; use itertools::Itertools;
use reqwest::{Client, ClientBuilder, Proxy, Response}; use reqwest::{Client, ClientBuilder, IntoUrl, Proxy, Request, Response, multipart};
use reqwest_middleware::{ClientWithMiddleware, Middleware}; use reqwest_middleware::{ClientWithMiddleware, Middleware};
use reqwest_retry::policies::ExponentialBackoff; use reqwest_retry::policies::ExponentialBackoff;
use reqwest_retry::{ use reqwest_retry::{
DefaultRetryableStrategy, RetryTransientMiddleware, Retryable, RetryableStrategy, DefaultRetryableStrategy, RetryTransientMiddleware, Retryable, RetryableStrategy,
}; };
use tracing::{debug, trace}; use tracing::{debug, trace};
use url::ParseError;
use url::Url; use url::Url;
use uv_auth::Credentials;
use uv_auth::{AuthMiddleware, Indexes}; use uv_auth::{AuthMiddleware, Indexes};
use uv_configuration::{KeyringProviderType, TrustedHost}; use uv_configuration::{KeyringProviderType, TrustedHost};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_pep508::MarkerEnvironment; use uv_pep508::MarkerEnvironment;
use uv_platform_tags::Platform; use uv_platform_tags::Platform;
use uv_redacted::DisplaySafeUrl;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_version::version; use uv_version::version;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
@ -31,6 +43,10 @@ use crate::middleware::OfflineMiddleware;
use crate::tls::read_identity; use crate::tls::read_identity;
pub const DEFAULT_RETRIES: u32 = 3; pub const DEFAULT_RETRIES: u32 = 3;
/// Maximum number of redirects to follow before giving up.
///
/// This is the default used by [`reqwest`].
const DEFAULT_MAX_REDIRECTS: u32 = 10;
/// Selectively skip parts or the entire auth middleware. /// Selectively skip parts or the entire auth middleware.
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@ -51,6 +67,7 @@ pub struct BaseClientBuilder<'a> {
keyring: KeyringProviderType, keyring: KeyringProviderType,
allow_insecure_host: Vec<TrustedHost>, allow_insecure_host: Vec<TrustedHost>,
native_tls: bool, native_tls: bool,
built_in_root_certs: bool,
retries: u32, retries: u32,
pub connectivity: Connectivity, pub connectivity: Connectivity,
markers: Option<&'a MarkerEnvironment>, markers: Option<&'a MarkerEnvironment>,
@ -60,6 +77,31 @@ pub struct BaseClientBuilder<'a> {
default_timeout: Duration, default_timeout: Duration,
extra_middleware: Option<ExtraMiddleware>, extra_middleware: Option<ExtraMiddleware>,
proxies: Vec<Proxy>, proxies: Vec<Proxy>,
redirect_policy: RedirectPolicy,
/// Whether credentials should be propagated during cross-origin redirects.
///
/// A policy allowing propagation is insecure and should only be available for test code.
cross_origin_credential_policy: CrossOriginCredentialsPolicy,
}
/// The policy for handling HTTP redirects.
#[derive(Debug, Default, Clone, Copy)]
pub enum RedirectPolicy {
/// Use reqwest's built-in redirect handling. This bypasses our custom middleware
/// on redirect.
#[default]
BypassMiddleware,
/// Handle redirects manually, re-triggering our custom middleware for each request.
RetriggerMiddleware,
}
impl RedirectPolicy {
pub fn reqwest_policy(self) -> reqwest::redirect::Policy {
match self {
RedirectPolicy::BypassMiddleware => reqwest::redirect::Policy::default(),
RedirectPolicy::RetriggerMiddleware => reqwest::redirect::Policy::none(),
}
}
} }
/// A list of user-defined middlewares to be applied to the client. /// A list of user-defined middlewares to be applied to the client.
@ -86,6 +128,7 @@ impl BaseClientBuilder<'_> {
keyring: KeyringProviderType::default(), keyring: KeyringProviderType::default(),
allow_insecure_host: vec![], allow_insecure_host: vec![],
native_tls: false, native_tls: false,
built_in_root_certs: false,
connectivity: Connectivity::Online, connectivity: Connectivity::Online,
retries: DEFAULT_RETRIES, retries: DEFAULT_RETRIES,
markers: None, markers: None,
@ -95,6 +138,8 @@ impl BaseClientBuilder<'_> {
default_timeout: Duration::from_secs(30), default_timeout: Duration::from_secs(30),
extra_middleware: None, extra_middleware: None,
proxies: vec![], proxies: vec![],
redirect_policy: RedirectPolicy::default(),
cross_origin_credential_policy: CrossOriginCredentialsPolicy::Secure,
} }
} }
} }
@ -124,12 +169,37 @@ impl<'a> BaseClientBuilder<'a> {
self self
} }
/// Read the retry count from [`EnvVars::UV_HTTP_RETRIES`] if set, otherwise, make no change.
///
/// Errors when [`EnvVars::UV_HTTP_RETRIES`] is not a valid u32.
pub fn retries_from_env(self) -> anyhow::Result<Self> {
// TODO(zanieb): We should probably parse this in another layer, but there's not a natural
// fit for it right now
if let Some(value) = env::var_os(EnvVars::UV_HTTP_RETRIES) {
Ok(self.retries(
value
.to_string_lossy()
.as_ref()
.parse::<u32>()
.context("Failed to parse `UV_HTTP_RETRIES`")?,
))
} else {
Ok(self)
}
}
#[must_use] #[must_use]
pub fn native_tls(mut self, native_tls: bool) -> Self { pub fn native_tls(mut self, native_tls: bool) -> Self {
self.native_tls = native_tls; self.native_tls = native_tls;
self self
} }
#[must_use]
pub fn built_in_root_certs(mut self, built_in_root_certs: bool) -> Self {
self.built_in_root_certs = built_in_root_certs;
self
}
#[must_use] #[must_use]
pub fn markers(mut self, markers: &'a MarkerEnvironment) -> Self { pub fn markers(mut self, markers: &'a MarkerEnvironment) -> Self {
self.markers = Some(markers); self.markers = Some(markers);
@ -172,13 +242,35 @@ impl<'a> BaseClientBuilder<'a> {
self self
} }
#[must_use]
pub fn redirect(mut self, policy: RedirectPolicy) -> Self {
self.redirect_policy = policy;
self
}
/// Allows credentials to be propagated on cross-origin redirects.
///
/// WARNING: This should only be available for tests. In production code, propagating credentials
/// during cross-origin redirects can lead to security vulnerabilities including credential
/// leakage to untrusted domains.
#[cfg(test)]
#[must_use]
pub fn allow_cross_origin_credentials(mut self) -> Self {
self.cross_origin_credential_policy = CrossOriginCredentialsPolicy::Insecure;
self
}
pub fn is_offline(&self) -> bool { pub fn is_offline(&self) -> bool {
matches!(self.connectivity, Connectivity::Offline) matches!(self.connectivity, Connectivity::Offline)
} }
/// Create a [`RetryPolicy`] for the client. /// Create a [`RetryPolicy`] for the client.
fn retry_policy(&self) -> ExponentialBackoff { fn retry_policy(&self) -> ExponentialBackoff {
ExponentialBackoff::builder().build_with_max_retries(self.retries) let mut builder = ExponentialBackoff::builder();
if env::var_os(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY).is_some() {
builder = builder.retry_bounds(Duration::from_millis(0), Duration::from_millis(0));
}
builder.build_with_max_retries(self.retries)
} }
pub fn build(&self) -> BaseClient { pub fn build(&self) -> BaseClient {
@ -228,6 +320,7 @@ impl<'a> BaseClientBuilder<'a> {
timeout, timeout,
ssl_cert_file_exists, ssl_cert_file_exists,
Security::Secure, Security::Secure,
self.redirect_policy,
); );
// Create an insecure client that accepts invalid certificates. // Create an insecure client that accepts invalid certificates.
@ -236,11 +329,20 @@ impl<'a> BaseClientBuilder<'a> {
timeout, timeout,
ssl_cert_file_exists, ssl_cert_file_exists,
Security::Insecure, Security::Insecure,
self.redirect_policy,
); );
// Wrap in any relevant middleware and handle connectivity. // Wrap in any relevant middleware and handle connectivity.
let client = self.apply_middleware(raw_client.clone()); let client = RedirectClientWithMiddleware {
let dangerous_client = self.apply_middleware(raw_dangerous_client.clone()); client: self.apply_middleware(raw_client.clone()),
redirect_policy: self.redirect_policy,
cross_origin_credentials_policy: self.cross_origin_credential_policy,
};
let dangerous_client = RedirectClientWithMiddleware {
client: self.apply_middleware(raw_dangerous_client.clone()),
redirect_policy: self.redirect_policy,
cross_origin_credentials_policy: self.cross_origin_credential_policy,
};
BaseClient { BaseClient {
connectivity: self.connectivity, connectivity: self.connectivity,
@ -257,8 +359,16 @@ impl<'a> BaseClientBuilder<'a> {
/// Share the underlying client between two different middleware configurations. /// Share the underlying client between two different middleware configurations.
pub fn wrap_existing(&self, existing: &BaseClient) -> BaseClient { pub fn wrap_existing(&self, existing: &BaseClient) -> BaseClient {
// Wrap in any relevant middleware and handle connectivity. // Wrap in any relevant middleware and handle connectivity.
let client = self.apply_middleware(existing.raw_client.clone()); let client = RedirectClientWithMiddleware {
let dangerous_client = self.apply_middleware(existing.raw_dangerous_client.clone()); client: self.apply_middleware(existing.raw_client.clone()),
redirect_policy: self.redirect_policy,
cross_origin_credentials_policy: self.cross_origin_credential_policy,
};
let dangerous_client = RedirectClientWithMiddleware {
client: self.apply_middleware(existing.raw_dangerous_client.clone()),
redirect_policy: self.redirect_policy,
cross_origin_credentials_policy: self.cross_origin_credential_policy,
};
BaseClient { BaseClient {
connectivity: self.connectivity, connectivity: self.connectivity,
@ -278,6 +388,7 @@ impl<'a> BaseClientBuilder<'a> {
timeout: Duration, timeout: Duration,
ssl_cert_file_exists: bool, ssl_cert_file_exists: bool,
security: Security, security: Security,
redirect_policy: RedirectPolicy,
) -> Client { ) -> Client {
// Configure the builder. // Configure the builder.
let client_builder = ClientBuilder::new() let client_builder = ClientBuilder::new()
@ -285,7 +396,8 @@ impl<'a> BaseClientBuilder<'a> {
.user_agent(user_agent) .user_agent(user_agent)
.pool_max_idle_per_host(20) .pool_max_idle_per_host(20)
.read_timeout(timeout) .read_timeout(timeout)
.tls_built_in_root_certs(false); .tls_built_in_root_certs(self.built_in_root_certs)
.redirect(redirect_policy.reqwest_policy());
// If necessary, accept invalid certificates. // If necessary, accept invalid certificates.
let client_builder = match security { let client_builder = match security {
@ -380,9 +492,9 @@ impl<'a> BaseClientBuilder<'a> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BaseClient { pub struct BaseClient {
/// The underlying HTTP client that enforces valid certificates. /// The underlying HTTP client that enforces valid certificates.
client: ClientWithMiddleware, client: RedirectClientWithMiddleware,
/// The underlying HTTP client that accepts invalid certificates. /// The underlying HTTP client that accepts invalid certificates.
dangerous_client: ClientWithMiddleware, dangerous_client: RedirectClientWithMiddleware,
/// The HTTP client without middleware. /// The HTTP client without middleware.
raw_client: Client, raw_client: Client,
/// The HTTP client that accepts invalid certificates without middleware. /// The HTTP client that accepts invalid certificates without middleware.
@ -407,7 +519,7 @@ enum Security {
impl BaseClient { impl BaseClient {
/// Selects the appropriate client based on the host's trustworthiness. /// Selects the appropriate client based on the host's trustworthiness.
pub fn for_host(&self, url: &Url) -> &ClientWithMiddleware { pub fn for_host(&self, url: &DisplaySafeUrl) -> &RedirectClientWithMiddleware {
if self.disable_ssl(url) { if self.disable_ssl(url) {
&self.dangerous_client &self.dangerous_client
} else { } else {
@ -415,8 +527,14 @@ impl BaseClient {
} }
} }
/// Executes a request, applying redirect policy.
pub async fn execute(&self, req: Request) -> reqwest_middleware::Result<Response> {
let client = self.for_host(&DisplaySafeUrl::from(req.url().clone()));
client.execute(req).await
}
/// Returns `true` if the host is trusted to use the insecure client. /// Returns `true` if the host is trusted to use the insecure client.
pub fn disable_ssl(&self, url: &Url) -> bool { pub fn disable_ssl(&self, url: &DisplaySafeUrl) -> bool {
self.allow_insecure_host self.allow_insecure_host
.iter() .iter()
.any(|allow_insecure_host| allow_insecure_host.matches(url)) .any(|allow_insecure_host| allow_insecure_host.matches(url))
@ -438,6 +556,326 @@ impl BaseClient {
} }
} }
/// Wrapper around [`ClientWithMiddleware`] that manages redirects.
#[derive(Debug, Clone)]
pub struct RedirectClientWithMiddleware {
client: ClientWithMiddleware,
redirect_policy: RedirectPolicy,
/// Whether credentials should be preserved during cross-origin redirects.
///
/// WARNING: This should only be available for tests. In production code, preserving credentials
/// during cross-origin redirects can lead to security vulnerabilities including credential
/// leakage to untrusted domains.
cross_origin_credentials_policy: CrossOriginCredentialsPolicy,
}
impl RedirectClientWithMiddleware {
/// Convenience method to make a `GET` request to a URL.
pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder {
RequestBuilder::new(self.client.get(url), self)
}
/// Convenience method to make a `POST` request to a URL.
pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder {
RequestBuilder::new(self.client.post(url), self)
}
/// Convenience method to make a `HEAD` request to a URL.
pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder {
RequestBuilder::new(self.client.head(url), self)
}
/// Executes a request, applying the redirect policy.
pub async fn execute(&self, req: Request) -> reqwest_middleware::Result<Response> {
match self.redirect_policy {
RedirectPolicy::BypassMiddleware => self.client.execute(req).await,
RedirectPolicy::RetriggerMiddleware => self.execute_with_redirect_handling(req).await,
}
}
/// Executes a request. If the response is a redirect (one of HTTP 301, 302, 303, 307, or 308), the
/// request is executed again with the redirect location URL (up to a maximum number of
/// redirects).
///
/// Unlike the built-in reqwest redirect policies, this sends the redirect request through the
/// entire middleware pipeline again.
///
/// See RFC 7231 7.1.2 <https://www.rfc-editor.org/rfc/rfc7231#section-7.1.2> for details on
/// redirect semantics.
async fn execute_with_redirect_handling(
&self,
req: Request,
) -> reqwest_middleware::Result<Response> {
let mut request = req;
let mut redirects = 0;
let max_redirects = DEFAULT_MAX_REDIRECTS;
loop {
let result = self
.client
.execute(request.try_clone().expect("HTTP request must be cloneable"))
.await;
let Ok(response) = result else {
return result;
};
if redirects >= max_redirects {
return Ok(response);
}
let Some(redirect_request) =
request_into_redirect(request, &response, self.cross_origin_credentials_policy)?
else {
return Ok(response);
};
redirects += 1;
request = redirect_request;
}
}
pub fn raw_client(&self) -> &ClientWithMiddleware {
&self.client
}
}
impl From<RedirectClientWithMiddleware> for ClientWithMiddleware {
fn from(item: RedirectClientWithMiddleware) -> ClientWithMiddleware {
item.client
}
}
/// Check if this is should be a redirect and, if so, return a new redirect request.
///
/// This implementation is based on the [`reqwest`] crate redirect implementation.
/// It takes ownership of the original [`Request`] and mutates it to create the new
/// redirect [`Request`].
fn request_into_redirect(
mut req: Request,
res: &Response,
cross_origin_credentials_policy: CrossOriginCredentialsPolicy,
) -> reqwest_middleware::Result<Option<Request>> {
let original_req_url = DisplaySafeUrl::from(req.url().clone());
let status = res.status();
let should_redirect = match status {
StatusCode::MOVED_PERMANENTLY
| StatusCode::FOUND
| StatusCode::TEMPORARY_REDIRECT
| StatusCode::PERMANENT_REDIRECT => true,
StatusCode::SEE_OTHER => {
// Per RFC 7231, HTTP 303 is intended for the user agent
// to perform a GET or HEAD request to the redirect target.
// Historically, some browsers also changed method from POST
// to GET on 301 or 302, but this is not required by RFC 7231
// and was not intended by the HTTP spec.
*req.body_mut() = None;
for header in &[
TRANSFER_ENCODING,
CONTENT_ENCODING,
CONTENT_TYPE,
CONTENT_LENGTH,
] {
req.headers_mut().remove(header);
}
match *req.method() {
Method::GET | Method::HEAD => {}
_ => {
*req.method_mut() = Method::GET;
}
}
true
}
_ => false,
};
if !should_redirect {
return Ok(None);
}
let location = res
.headers()
.get(LOCATION)
.ok_or(reqwest_middleware::Error::Middleware(anyhow!(
"Server returned redirect (HTTP {status}) without destination URL. This may indicate a server configuration issue"
)))?
.to_str()
.map_err(|_| {
reqwest_middleware::Error::Middleware(anyhow!(
"Invalid HTTP {status} 'Location' value: must only contain visible ascii characters"
))
})?;
let mut redirect_url = match DisplaySafeUrl::parse(location) {
Ok(url) => url,
// Per RFC 7231, URLs should be resolved against the request URL.
Err(ParseError::RelativeUrlWithoutBase) => original_req_url.join(location).map_err(|err| {
reqwest_middleware::Error::Middleware(anyhow!(
"Invalid HTTP {status} 'Location' value `{location}` relative to `{original_req_url}`: {err}"
))
})?,
Err(err) => {
return Err(reqwest_middleware::Error::Middleware(anyhow!(
"Invalid HTTP {status} 'Location' value `{location}`: {err}"
)));
}
};
// Per RFC 7231, fragments must be propagated
if let Some(fragment) = original_req_url.fragment() {
redirect_url.set_fragment(Some(fragment));
}
// Ensure the URL is a valid HTTP URI.
if let Err(err) = redirect_url.as_str().parse::<http::Uri>() {
return Err(reqwest_middleware::Error::Middleware(anyhow!(
"HTTP {status} 'Location' value `{redirect_url}` is not a valid HTTP URI: {err}"
)));
}
if redirect_url.scheme() != "http" && redirect_url.scheme() != "https" {
return Err(reqwest_middleware::Error::Middleware(anyhow!(
"Invalid HTTP {status} 'Location' value `{redirect_url}`: scheme needs to be https or http"
)));
}
let mut headers = HeaderMap::new();
std::mem::swap(req.headers_mut(), &mut headers);
let cross_host = redirect_url.host_str() != original_req_url.host_str()
|| redirect_url.port_or_known_default() != original_req_url.port_or_known_default();
if cross_host {
if cross_origin_credentials_policy == CrossOriginCredentialsPolicy::Secure {
debug!("Received a cross-origin redirect. Removing sensitive headers.");
headers.remove(AUTHORIZATION);
headers.remove(COOKIE);
headers.remove(PROXY_AUTHORIZATION);
headers.remove(WWW_AUTHENTICATE);
}
// If the redirect request is not a cross-origin request and the original request already
// had a Referer header, attempt to set the Referer header for the redirect request.
} else if headers.contains_key(REFERER) {
if let Some(referer) = make_referer(&redirect_url, &original_req_url) {
headers.insert(REFERER, referer);
}
}
// Check if there are credentials on the redirect location itself.
// If so, move them to Authorization header.
if !redirect_url.username().is_empty() {
if let Some(credentials) = Credentials::from_url(&redirect_url) {
let _ = redirect_url.set_username("");
let _ = redirect_url.set_password(None);
headers.insert(AUTHORIZATION, credentials.to_header_value());
}
}
std::mem::swap(req.headers_mut(), &mut headers);
*req.url_mut() = Url::from(redirect_url);
debug!(
"Received HTTP {status}. Redirecting to {}",
DisplaySafeUrl::ref_cast(req.url())
);
Ok(Some(req))
}
/// Return a Referer [`HeaderValue`] according to RFC 7231.
///
/// Return [`None`] if https has been downgraded in the redirect location.
fn make_referer(
redirect_url: &DisplaySafeUrl,
original_url: &DisplaySafeUrl,
) -> Option<HeaderValue> {
if redirect_url.scheme() == "http" && original_url.scheme() == "https" {
return None;
}
let mut referer = original_url.clone();
referer.remove_credentials();
referer.set_fragment(None);
referer.as_str().parse().ok()
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub(crate) enum CrossOriginCredentialsPolicy {
/// Do not propagate credentials on cross-origin requests.
#[default]
Secure,
/// Propagate credentials on cross-origin requests.
///
/// WARNING: This should only be available for tests. In production code, preserving credentials
/// during cross-origin redirects can lead to security vulnerabilities including credential
/// leakage to untrusted domains.
#[cfg(test)]
Insecure,
}
/// A builder to construct the properties of a `Request`.
///
/// This wraps [`reqwest_middleware::RequestBuilder`] to ensure that the [`BaseClient`]
/// redirect policy is respected if `send()` is called.
#[derive(Debug)]
#[must_use]
pub struct RequestBuilder<'a> {
builder: reqwest_middleware::RequestBuilder,
client: &'a RedirectClientWithMiddleware,
}
impl<'a> RequestBuilder<'a> {
pub fn new(
builder: reqwest_middleware::RequestBuilder,
client: &'a RedirectClientWithMiddleware,
) -> Self {
Self { builder, client }
}
/// Add a `Header` to this Request.
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
{
self.builder = self.builder.header(key, value);
self
}
/// Add a set of Headers to the existing ones on this Request.
///
/// The headers will be merged in to any already set.
pub fn headers(mut self, headers: HeaderMap) -> Self {
self.builder = self.builder.headers(headers);
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn version(mut self, version: reqwest::Version) -> Self {
self.builder = self.builder.version(version);
self
}
#[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
pub fn multipart(mut self, multipart: multipart::Form) -> Self {
self.builder = self.builder.multipart(multipart);
self
}
/// Build a `Request`.
pub fn build(self) -> reqwest::Result<Request> {
self.builder.build()
}
/// Constructs the Request and sends it to the target URL, returning a
/// future Response.
pub async fn send(self) -> reqwest_middleware::Result<Response> {
self.client.execute(self.build()?).await
}
pub fn raw_builder(&self) -> &reqwest_middleware::RequestBuilder {
&self.builder
}
}
/// Extends [`DefaultRetryableStrategy`], to log transient request failures and additional retry cases. /// Extends [`DefaultRetryableStrategy`], to log transient request failures and additional retry cases.
pub struct UvRetryableStrategy; pub struct UvRetryableStrategy;
@ -490,18 +928,34 @@ pub fn is_extended_transient_error(err: &dyn Error) -> bool {
} }
// IO Errors may be nested through custom IO errors. // IO Errors may be nested through custom IO errors.
let mut has_io_error = false;
for io_err in find_sources::<io::Error>(&err) { for io_err in find_sources::<io::Error>(&err) {
if io_err.kind() == io::ErrorKind::ConnectionReset has_io_error = true;
|| io_err.kind() == io::ErrorKind::UnexpectedEof let retryable_io_err_kinds = [
|| io_err.kind() == io::ErrorKind::BrokenPipe // https://github.com/astral-sh/uv/issues/12054
{ io::ErrorKind::BrokenPipe,
trace!("Retrying error: `ConnectionReset` or `UnexpectedEof`"); // From reqwest-middleware
io::ErrorKind::ConnectionAborted,
// https://github.com/astral-sh/uv/issues/3514
io::ErrorKind::ConnectionReset,
// https://github.com/astral-sh/uv/issues/14699
io::ErrorKind::InvalidData,
// https://github.com/astral-sh/uv/issues/9246
io::ErrorKind::UnexpectedEof,
];
if retryable_io_err_kinds.contains(&io_err.kind()) {
trace!("Retrying error: `{}`", io_err.kind());
return true; return true;
} }
trace!("Cannot retry IO error: not one of `ConnectionReset` or `UnexpectedEof`"); trace!(
"Cannot retry IO error `{}`, not a retryable IO error kind",
io_err.kind()
);
} }
trace!("Cannot retry error: not an IO error"); if !has_io_error {
trace!("Cannot retry error: not an extended IO error");
}
false false
} }
@ -527,3 +981,204 @@ fn find_source<E: Error + 'static>(orig: &dyn Error) -> Option<&E> {
fn find_sources<E: Error + 'static>(orig: &dyn Error) -> impl Iterator<Item = &E> { fn find_sources<E: Error + 'static>(orig: &dyn Error) -> impl Iterator<Item = &E> {
iter::successors(find_source::<E>(orig), |&err| find_source(err)) iter::successors(find_source::<E>(orig), |&err| find_source(err))
} }
#[cfg(test)]
mod tests {
use super::*;
use anyhow::Result;
use reqwest::{Client, Method};
use wiremock::matchers::method;
use wiremock::{Mock, MockServer, ResponseTemplate};
use crate::base_client::request_into_redirect;
#[tokio::test]
async fn test_redirect_preserves_authorization_header_on_same_origin() -> 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(server.uri())
.basic_auth("username", Some("password"))
.build()
.unwrap();
assert!(request.headers().contains_key(AUTHORIZATION));
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.headers().contains_key(AUTHORIZATION));
}
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] {
let server = MockServer::start().await;
Mock::given(method("GET"))
.respond_with(
ResponseTemplate::new(*status)
.insert_header("location", "https://cross-origin.com/simple"),
)
.mount(&server)
.await;
let request = Client::new()
.get(server.uri())
.basic_auth("username", Some("password"))
.build()
.unwrap();
assert!(request.headers().contains_key(AUTHORIZATION));
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.headers().contains_key(AUTHORIZATION));
}
Ok(())
}
#[tokio::test]
async fn test_redirect_303_changes_post_to_get() -> Result<()> {
let server = MockServer::start().await;
Mock::given(method("POST"))
.respond_with(
ResponseTemplate::new(303)
.insert_header("location", format!("{}/redirect", server.uri())),
)
.mount(&server)
.await;
let request = Client::new()
.post(server.uri())
.basic_auth("username", Some("password"))
.build()
.unwrap();
assert_eq!(request.method(), Method::POST);
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_eq!(redirect_request.method(), Method::GET);
Ok(())
}
#[tokio::test]
async fn test_redirect_no_referer_if_disabled() -> 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::builder()
.referer(false)
.build()
.unwrap()
.get(server.uri())
.basic_auth("username", Some("password"))
.build()
.unwrap();
assert!(!request.headers().contains_key(REFERER));
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.headers().contains_key(REFERER));
}
Ok(())
}
}

View file

@ -1,4 +1,3 @@
use std::fmt::{Debug, Display, Formatter};
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use std::{borrow::Cow, path::Path}; use std::{borrow::Cow, path::Path};
@ -12,6 +11,7 @@ use tracing::{Instrument, debug, info_span, instrument, trace, warn};
use uv_cache::{CacheEntry, Freshness}; use uv_cache::{CacheEntry, Freshness};
use uv_fs::write_atomic; use uv_fs::write_atomic;
use uv_redacted::DisplaySafeUrl;
use crate::BaseClient; use crate::BaseClient;
use crate::base_client::is_extended_transient_error; use crate::base_client::is_extended_transient_error;
@ -99,44 +99,62 @@ where
} }
} }
/// Either a cached client error or a (user specified) error from the callback /// Dispatch type: Either a cached client error or a (user specified) error from the callback
pub enum CachedClientError<CallbackError: std::error::Error + 'static> { pub enum CachedClientError<CallbackError: std::error::Error + 'static> {
Client(Error), Client {
Callback(CallbackError), retries: Option<u32>,
err: Error,
},
Callback {
retries: Option<u32>,
err: CallbackError,
},
} }
impl<CallbackError: std::error::Error + 'static> Display for CachedClientError<CallbackError> { impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { /// Attach the number of retries to the error context.
///
/// Adds to existing errors if any, in case different layers retried.
fn with_retries(self, retries: u32) -> Self {
match self { match self {
CachedClientError::Client(err) => write!(f, "{err}"), CachedClientError::Client {
CachedClientError::Callback(err) => write!(f, "{err}"), retries: existing_retries,
err,
} => CachedClientError::Client {
retries: Some(existing_retries.unwrap_or_default() + retries),
err,
},
CachedClientError::Callback {
retries: existing_retries,
err,
} => CachedClientError::Callback {
retries: Some(existing_retries.unwrap_or_default() + retries),
err,
},
} }
} }
}
impl<CallbackError: std::error::Error + 'static> Debug for CachedClientError<CallbackError> { fn retries(&self) -> Option<u32> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
CachedClientError::Client(err) => write!(f, "{err:?}"), CachedClientError::Client { retries, .. } => *retries,
CachedClientError::Callback(err) => write!(f, "{err:?}"), CachedClientError::Callback { retries, .. } => *retries,
} }
} }
}
impl<CallbackError: std::error::Error + 'static> std::error::Error fn error(&self) -> &dyn std::error::Error {
for CachedClientError<CallbackError>
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self { match self {
CachedClientError::Client(err) => Some(err), CachedClientError::Client { err, .. } => err,
CachedClientError::Callback(err) => Some(err), CachedClientError::Callback { err, .. } => err,
} }
} }
} }
impl<CallbackError: std::error::Error + 'static> From<Error> for CachedClientError<CallbackError> { impl<CallbackError: std::error::Error + 'static> From<Error> for CachedClientError<CallbackError> {
fn from(error: Error) -> Self { fn from(error: Error) -> Self {
Self::Client(error) Self::Client {
retries: None,
err: error,
}
} }
} }
@ -144,30 +162,44 @@ impl<CallbackError: std::error::Error + 'static> From<ErrorKind>
for CachedClientError<CallbackError> for CachedClientError<CallbackError>
{ {
fn from(error: ErrorKind) -> Self { fn from(error: ErrorKind) -> Self {
Self::Client(error.into()) Self::Client {
retries: None,
err: error.into(),
}
} }
} }
impl<E: Into<Self> + std::error::Error + 'static> From<CachedClientError<E>> for Error { impl<E: Into<Self> + std::error::Error + 'static> From<CachedClientError<E>> for Error {
/// Attach retry error context, if there were retries.
fn from(error: CachedClientError<E>) -> Self { fn from(error: CachedClientError<E>) -> Self {
match error { match error {
CachedClientError::Client(error) => error, CachedClientError::Client {
CachedClientError::Callback(error) => error.into(), retries: Some(retries),
err,
} => Error::new(err.into_kind(), retries),
CachedClientError::Client { retries: None, err } => err,
CachedClientError::Callback {
retries: Some(retries),
err,
} => Error::new(err.into().into_kind(), retries),
CachedClientError::Callback { retries: None, err } => err.into(),
} }
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CacheControl { pub enum CacheControl<'a> {
/// Respect the `cache-control` header from the response. /// Respect the `cache-control` header from the response.
None, None,
/// Apply `max-age=0, must-revalidate` to the request. /// Apply `max-age=0, must-revalidate` to the request.
MustRevalidate, MustRevalidate,
/// Allow the client to return stale responses. /// Allow the client to return stale responses.
AllowStale, AllowStale,
/// Override the cache control header with a custom value.
Override(&'a str),
} }
impl From<Freshness> for CacheControl { impl From<Freshness> for CacheControl<'_> {
fn from(value: Freshness) -> Self { fn from(value: Freshness) -> Self {
match value { match value {
Freshness::Fresh => Self::None, Freshness::Fresh => Self::None,
@ -221,7 +253,7 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl, cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload, CachedClientError<CallBackError>> { ) -> Result<Payload, CachedClientError<CallBackError>> {
let payload = self let payload = self
@ -254,7 +286,7 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl, cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload::Target, CachedClientError<CallBackError>> { ) -> Result<Payload::Target, CachedClientError<CallBackError>> {
let fresh_req = req.try_clone().expect("HTTP request must be cloneable"); let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
@ -264,7 +296,7 @@ impl CachedClient {
.await? .await?
} else { } else {
debug!("No cache entry for: {}", req.url()); debug!("No cache entry for: {}", req.url());
let (response, cache_policy) = self.fresh_request(req).await?; let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
CachedResponse::ModifiedOrNew { CachedResponse::ModifiedOrNew {
response, response,
cache_policy, cache_policy,
@ -278,7 +310,12 @@ impl CachedClient {
"Broken fresh cache entry (for payload) at {}, removing: {err}", "Broken fresh cache entry (for payload) at {}, removing: {err}",
cache_entry.path().display() cache_entry.path().display()
); );
self.resend_and_heal_cache(fresh_req, cache_entry, response_callback) self.resend_and_heal_cache(
fresh_req,
cache_entry,
cache_control,
response_callback,
)
.await .await
} }
}, },
@ -299,7 +336,12 @@ impl CachedClient {
(for payload) at {}, removing: {err}", (for payload) at {}, removing: {err}",
cache_entry.path().display() cache_entry.path().display()
); );
self.resend_and_heal_cache(fresh_req, cache_entry, response_callback) self.resend_and_heal_cache(
fresh_req,
cache_entry,
cache_control,
response_callback,
)
.await .await
} }
} }
@ -315,7 +357,12 @@ impl CachedClient {
// ETag didn't match). We need to make a fresh request. // ETag didn't match). We need to make a fresh request.
if response.status() == http::StatusCode::NOT_MODIFIED { if response.status() == http::StatusCode::NOT_MODIFIED {
warn!("Server returned unusable 304 for: {}", fresh_req.url()); warn!("Server returned unusable 304 for: {}", fresh_req.url());
self.resend_and_heal_cache(fresh_req, cache_entry, response_callback) self.resend_and_heal_cache(
fresh_req,
cache_entry,
cache_control,
response_callback,
)
.await .await
} else { } else {
self.run_response_callback( self.run_response_callback(
@ -339,9 +386,10 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload, CachedClientError<CallBackError>> { ) -> Result<Payload, CachedClientError<CallBackError>> {
let (response, cache_policy) = self.fresh_request(req).await?; let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
let payload = self let payload = self
.run_response_callback(cache_entry, cache_policy, response, async |resp| { .run_response_callback(cache_entry, cache_policy, response, async |resp| {
@ -361,10 +409,11 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload::Target, CachedClientError<CallBackError>> { ) -> Result<Payload::Target, CachedClientError<CallBackError>> {
let _ = fs_err::tokio::remove_file(&cache_entry.path()).await; let _ = fs_err::tokio::remove_file(&cache_entry.path()).await;
let (response, cache_policy) = self.fresh_request(req).await?; let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
self.run_response_callback(cache_entry, cache_policy, response, response_callback) self.run_response_callback(cache_entry, cache_policy, response, response_callback)
.await .await
} }
@ -384,7 +433,7 @@ impl CachedClient {
let data = response_callback(response) let data = response_callback(response)
.boxed_local() .boxed_local()
.await .await
.map_err(|err| CachedClientError::Callback(err))?; .map_err(|err| CachedClientError::Callback { retries: None, err })?;
let Some(cache_policy) = cache_policy else { let Some(cache_policy) = cache_policy else {
return Ok(data.into_target()); return Ok(data.into_target());
}; };
@ -431,12 +480,12 @@ impl CachedClient {
async fn send_cached( async fn send_cached(
&self, &self,
mut req: Request, mut req: Request,
cache_control: CacheControl, cache_control: CacheControl<'_>,
cached: DataWithCachePolicy, cached: DataWithCachePolicy,
) -> Result<CachedResponse, Error> { ) -> Result<CachedResponse, Error> {
// Apply the cache control header, if necessary. // Apply the cache control header, if necessary.
match cache_control { match cache_control {
CacheControl::None | CacheControl::AllowStale => {} CacheControl::None | CacheControl::AllowStale | CacheControl::Override(..) => {}
CacheControl::MustRevalidate => { CacheControl::MustRevalidate => {
req.headers_mut().insert( req.headers_mut().insert(
http::header::CACHE_CONTROL, http::header::CACHE_CONTROL,
@ -450,9 +499,14 @@ impl CachedClient {
CachedResponse::FreshCache(cached) CachedResponse::FreshCache(cached)
} }
BeforeRequest::Stale(new_cache_policy_builder) => match cache_control { BeforeRequest::Stale(new_cache_policy_builder) => match cache_control {
CacheControl::None | CacheControl::MustRevalidate => { CacheControl::None | CacheControl::MustRevalidate | CacheControl::Override(_) => {
debug!("Found stale response for: {}", req.url()); debug!("Found stale response for: {}", req.url());
self.send_cached_handle_stale(req, cached, new_cache_policy_builder) self.send_cached_handle_stale(
req,
cache_control,
cached,
new_cache_policy_builder,
)
.await? .await?
} }
CacheControl::AllowStale => { CacheControl::AllowStale => {
@ -466,7 +520,7 @@ impl CachedClient {
"Cached request doesn't match current request for: {}", "Cached request doesn't match current request for: {}",
req.url() req.url()
); );
let (response, cache_policy) = self.fresh_request(req).await?; let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
CachedResponse::ModifiedOrNew { CachedResponse::ModifiedOrNew {
response, response,
cache_policy, cache_policy,
@ -478,20 +532,30 @@ impl CachedClient {
async fn send_cached_handle_stale( async fn send_cached_handle_stale(
&self, &self,
req: Request, req: Request,
cache_control: CacheControl<'_>,
cached: DataWithCachePolicy, cached: DataWithCachePolicy,
new_cache_policy_builder: CachePolicyBuilder, new_cache_policy_builder: CachePolicyBuilder,
) -> Result<CachedResponse, Error> { ) -> Result<CachedResponse, Error> {
let url = req.url().clone(); let url = DisplaySafeUrl::from(req.url().clone());
debug!("Sending revalidation request for: {url}"); debug!("Sending revalidation request for: {url}");
let response = self let mut response = self
.0 .0
.for_host(req.url())
.execute(req) .execute(req)
.instrument(info_span!("revalidation_request", url = url.as_str())) .instrument(info_span!("revalidation_request", url = url.as_str()))
.await .await
.map_err(|err| ErrorKind::from_reqwest_middleware(url.clone(), err))? .map_err(|err| ErrorKind::from_reqwest_middleware(url.clone(), err))?
.error_for_status() .error_for_status()
.map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?; .map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?;
// If the user set a custom `Cache-Control` header, override it.
if let CacheControl::Override(header) = cache_control {
response.headers_mut().insert(
http::header::CACHE_CONTROL,
http::HeaderValue::from_str(header)
.expect("Cache-Control header must be valid UTF-8"),
);
}
match cached match cached
.cache_policy .cache_policy
.after_response(new_cache_policy_builder, &response) .after_response(new_cache_policy_builder, &response)
@ -520,18 +584,39 @@ impl CachedClient {
async fn fresh_request( async fn fresh_request(
&self, &self,
req: Request, req: Request,
cache_control: CacheControl<'_>,
) -> Result<(Response, Option<Box<CachePolicy>>), Error> { ) -> Result<(Response, Option<Box<CachePolicy>>), Error> {
let url = req.url().clone(); let url = DisplaySafeUrl::from(req.url().clone());
trace!("Sending fresh {} request for {}", req.method(), url); trace!("Sending fresh {} request for {}", req.method(), url);
let cache_policy_builder = CachePolicyBuilder::new(&req); let cache_policy_builder = CachePolicyBuilder::new(&req);
let response = self let mut response = self
.0 .0
.for_host(&url)
.execute(req) .execute(req)
.await .await
.map_err(|err| ErrorKind::from_reqwest_middleware(url.clone(), err))? .map_err(|err| ErrorKind::from_reqwest_middleware(url.clone(), err))?;
.error_for_status()
.map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?; // If the user set a custom `Cache-Control` header, override it.
if let CacheControl::Override(header) = cache_control {
response.headers_mut().insert(
http::header::CACHE_CONTROL,
http::HeaderValue::from_str(header)
.expect("Cache-Control header must be valid UTF-8"),
);
}
let retry_count = response
.extensions()
.get::<reqwest_retry::RetryCount>()
.map(|retries| retries.value());
if let Err(status_error) = response.error_for_status_ref() {
return Err(CachedClientError::<Error>::Client {
retries: retry_count,
err: ErrorKind::from_reqwest(url, status_error).into(),
}
.into());
}
let cache_policy = cache_policy_builder.build(&response); let cache_policy = cache_policy_builder.build(&response);
let cache_policy = if cache_policy.to_archived().is_storable() { let cache_policy = if cache_policy.to_archived().is_storable() {
Some(Box::new(cache_policy)) Some(Box::new(cache_policy))
@ -551,7 +636,7 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl, cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload, CachedClientError<CallBackError>> { ) -> Result<Payload, CachedClientError<CallBackError>> {
let payload = self let payload = self
@ -575,10 +660,10 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl, cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload::Target, CachedClientError<CallBackError>> { ) -> Result<Payload::Target, CachedClientError<CallBackError>> {
let mut n_past_retries = 0; let mut past_retries = 0;
let start_time = SystemTime::now(); let start_time = SystemTime::now();
let retry_policy = self.uncached().retry_policy(); let retry_policy = self.uncached().retry_policy();
loop { loop {
@ -586,11 +671,20 @@ impl CachedClient {
let result = self let result = self
.get_cacheable(fresh_req, cache_entry, cache_control, &response_callback) .get_cacheable(fresh_req, cache_entry, cache_control, &response_callback)
.await; .await;
// Check if the middleware already performed retries
let middleware_retries = match &result {
Err(err) => err.retries().unwrap_or_default(),
Ok(_) => 0,
};
if result if result
.as_ref() .as_ref()
.is_err_and(|err| is_extended_transient_error(err)) .is_err_and(|err| is_extended_transient_error(err.error()))
{ {
let retry_decision = retry_policy.should_retry(start_time, n_past_retries); // If middleware already retried, consider that in our retry budget
let total_retries = past_retries + middleware_retries;
let retry_decision = retry_policy.should_retry(start_time, total_retries);
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision { if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
debug!( debug!(
"Transient failure while handling response from {}; retrying...", "Transient failure while handling response from {}; retrying...",
@ -600,10 +694,15 @@ impl CachedClient {
.duration_since(SystemTime::now()) .duration_since(SystemTime::now())
.unwrap_or_else(|_| Duration::default()); .unwrap_or_else(|_| Duration::default());
tokio::time::sleep(duration).await; tokio::time::sleep(duration).await;
n_past_retries += 1; past_retries += 1;
continue; continue;
} }
} }
if past_retries > 0 {
return result.map_err(|err| err.with_retries(past_retries));
}
return result; return result;
} }
} }
@ -619,22 +718,31 @@ impl CachedClient {
&self, &self,
req: Request, req: Request,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl<'_>,
response_callback: Callback, response_callback: Callback,
) -> Result<Payload, CachedClientError<CallBackError>> { ) -> Result<Payload, CachedClientError<CallBackError>> {
let mut n_past_retries = 0; let mut past_retries = 0;
let start_time = SystemTime::now(); let start_time = SystemTime::now();
let retry_policy = self.uncached().retry_policy(); let retry_policy = self.uncached().retry_policy();
loop { loop {
let fresh_req = req.try_clone().expect("HTTP request must be cloneable"); let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
let result = self let result = self
.skip_cache(fresh_req, cache_entry, &response_callback) .skip_cache(fresh_req, cache_entry, cache_control, &response_callback)
.await; .await;
// Check if the middleware already performed retries
let middleware_retries = match &result {
Err(err) => err.retries().unwrap_or_default(),
_ => 0,
};
if result if result
.as_ref() .as_ref()
.err() .err()
.is_some_and(|err| is_extended_transient_error(err)) .is_some_and(|err| is_extended_transient_error(err.error()))
{ {
let retry_decision = retry_policy.should_retry(start_time, n_past_retries); let total_retries = past_retries + middleware_retries;
let retry_decision = retry_policy.should_retry(start_time, total_retries);
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision { if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
debug!( debug!(
"Transient failure while handling response from {}; retrying...", "Transient failure while handling response from {}; retrying...",
@ -644,10 +752,15 @@ impl CachedClient {
.duration_since(SystemTime::now()) .duration_since(SystemTime::now())
.unwrap_or_else(|_| Duration::default()); .unwrap_or_else(|_| Duration::default());
tokio::time::sleep(duration).await; tokio::time::sleep(duration).await;
n_past_retries += 1; past_retries += 1;
continue; continue;
} }
} }
if past_retries > 0 {
return result.map_err(|err| err.with_retries(past_retries));
}
return result; return result;
} }
} }

View file

@ -3,39 +3,75 @@ use std::ops::Deref;
use async_http_range_reader::AsyncHttpRangeReaderError; use async_http_range_reader::AsyncHttpRangeReaderError;
use async_zip::error::ZipError; use async_zip::error::ZipError;
use url::Url;
use uv_distribution_filename::{WheelFilename, WheelFilenameError}; use uv_distribution_filename::{WheelFilename, WheelFilenameError};
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_redacted::redacted_url; use uv_redacted::DisplaySafeUrl;
use crate::middleware::OfflineError; use crate::middleware::OfflineError;
use crate::{FlatIndexError, html}; use crate::{FlatIndexError, html};
#[derive(Debug, thiserror::Error)] #[derive(Debug)]
#[error(transparent)]
pub struct Error { pub struct Error {
kind: Box<ErrorKind>, kind: Box<ErrorKind>,
retries: u32,
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.retries > 0 {
write!(
f,
"Request failed after {retries} retries",
retries = self.retries
)
} else {
Display::fmt(&self.kind, f)
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if self.retries > 0 {
Some(&self.kind)
} else {
self.kind.source()
}
}
} }
impl Error { impl Error {
/// Convert this error into its [`ErrorKind`] variant. /// Create a new [`Error`] with the given [`ErrorKind`] and number of retries.
pub fn new(kind: ErrorKind, retries: u32) -> Self {
Self {
kind: Box::new(kind),
retries,
}
}
/// Return the number of retries that were attempted before this error was returned.
pub fn retries(&self) -> u32 {
self.retries
}
/// Convert this error into an [`ErrorKind`].
pub fn into_kind(self) -> ErrorKind { pub fn into_kind(self) -> ErrorKind {
*self.kind *self.kind
} }
/// Get a reference to the [`ErrorKind`] variant of this error. /// Return the [`ErrorKind`] of this error.
pub fn kind(&self) -> &ErrorKind { pub fn kind(&self) -> &ErrorKind {
&self.kind &self.kind
} }
/// Create a new error from a JSON parsing error. /// Create a new error from a JSON parsing error.
pub(crate) fn from_json_err(err: serde_json::Error, url: Url) -> Self { pub(crate) fn from_json_err(err: serde_json::Error, url: DisplaySafeUrl) -> Self {
ErrorKind::BadJson { source: err, url }.into() ErrorKind::BadJson { source: err, url }.into()
} }
/// Create a new error from an HTML parsing error. /// Create a new error from an HTML parsing error.
pub(crate) fn from_html_err(err: html::Error, url: Url) -> Self { pub(crate) fn from_html_err(err: html::Error, url: DisplaySafeUrl) -> Self {
ErrorKind::BadHtml { source: err, url }.into() ErrorKind::BadHtml { source: err, url }.into()
} }
@ -79,7 +115,7 @@ impl Error {
// The server returned a "Method Not Allowed" error, indicating it doesn't support // The server returned a "Method Not Allowed" error, indicating it doesn't support
// HEAD requests, so we can't check for range requests. // HEAD requests, so we can't check for range requests.
ErrorKind::WrappedReqwestError(_url, err) => { ErrorKind::WrappedReqwestError(_, err) => {
if let Some(status) = err.status() { if let Some(status) = err.status() {
// If the server doesn't support HEAD requests, we can't check for range // If the server doesn't support HEAD requests, we can't check for range
// requests. // requests.
@ -144,6 +180,7 @@ impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self { fn from(kind: ErrorKind) -> Self {
Self { Self {
kind: Box::new(kind), kind: Box::new(kind),
retries: 0,
} }
} }
} }
@ -153,17 +190,14 @@ pub enum ErrorKind {
#[error(transparent)] #[error(transparent)]
InvalidUrl(#[from] uv_distribution_types::ToUrlError), InvalidUrl(#[from] uv_distribution_types::ToUrlError),
#[error(transparent)]
JoinRelativeUrl(#[from] uv_pypi_types::JoinRelativeError),
#[error(transparent)] #[error(transparent)]
Flat(#[from] FlatIndexError), Flat(#[from] FlatIndexError),
#[error("Expected a file URL, but received: {0}")] #[error("Expected a file URL, but received: {0}")]
NonFileUrl(Url), NonFileUrl(DisplaySafeUrl),
#[error("Expected an index URL, but received non-base URL: {0}")] #[error("Expected an index URL, but received non-base URL: {0}")]
CannotBeABase(Url), CannotBeABase(DisplaySafeUrl),
#[error("Failed to read metadata: `{0}`")] #[error("Failed to read metadata: `{0}`")]
Metadata(String, #[source] uv_metadata::Error), Metadata(String, #[source] uv_metadata::Error),
@ -196,16 +230,29 @@ pub enum ErrorKind {
/// An error that happened while making a request or in a reqwest middleware. /// An error that happened while making a request or in a reqwest middleware.
#[error("Failed to fetch: `{0}`")] #[error("Failed to fetch: `{0}`")]
WrappedReqwestError(Url, #[source] WrappedReqwestError), WrappedReqwestError(DisplaySafeUrl, #[source] WrappedReqwestError),
#[error("Received some unexpected JSON from {}", redacted_url(url))] /// Add the number of failed retries to the error.
BadJson { source: serde_json::Error, url: Url }, #[error("Request failed after {retries} retries")]
RequestWithRetries {
source: Box<ErrorKind>,
retries: u32,
},
#[error("Received some unexpected HTML from {}", redacted_url(url))] #[error("Received some unexpected JSON from {}", url)]
BadHtml { source: html::Error, url: Url }, BadJson {
source: serde_json::Error,
url: DisplaySafeUrl,
},
#[error("Received some unexpected HTML from {}", url)]
BadHtml {
source: html::Error,
url: DisplaySafeUrl,
},
#[error("Failed to read zip with range requests: `{0}`")] #[error("Failed to read zip with range requests: `{0}`")]
AsyncHttpRangeReader(Url, #[source] AsyncHttpRangeReaderError), AsyncHttpRangeReader(DisplaySafeUrl, #[source] AsyncHttpRangeReaderError),
#[error("{0} is not a valid wheel filename")] #[error("{0} is not a valid wheel filename")]
WheelFilename(#[source] WheelFilenameError), WheelFilename(#[source] WheelFilenameError),
@ -232,13 +279,13 @@ pub enum ErrorKind {
Encode(#[source] rmp_serde::encode::Error), Encode(#[source] rmp_serde::encode::Error),
#[error("Missing `Content-Type` header for {0}")] #[error("Missing `Content-Type` header for {0}")]
MissingContentType(Url), MissingContentType(DisplaySafeUrl),
#[error("Invalid `Content-Type` header for {0}")] #[error("Invalid `Content-Type` header for {0}")]
InvalidContentTypeHeader(Url, #[source] http::header::ToStrError), InvalidContentTypeHeader(DisplaySafeUrl, #[source] http::header::ToStrError),
#[error("Unsupported `Content-Type` \"{1}\" for {0}. Expected JSON or HTML.")] #[error("Unsupported `Content-Type` \"{1}\" for {0}. Expected JSON or HTML.")]
UnsupportedMediaType(Url, String), UnsupportedMediaType(DisplaySafeUrl, String),
#[error("Reading from cache archive failed: {0}")] #[error("Reading from cache archive failed: {0}")]
ArchiveRead(String), ArchiveRead(String),
@ -250,14 +297,22 @@ pub enum ErrorKind {
"Network connectivity is disabled, but the requested data wasn't found in the cache for: `{0}`" "Network connectivity is disabled, but the requested data wasn't found in the cache for: `{0}`"
)] )]
Offline(String), Offline(String),
#[error("Invalid cache control header: `{0}`")]
InvalidCacheControl(String),
} }
impl ErrorKind { impl ErrorKind {
pub(crate) fn from_reqwest(url: Url, error: reqwest::Error) -> Self { /// Create an [`ErrorKind`] from a [`reqwest::Error`].
pub(crate) fn from_reqwest(url: DisplaySafeUrl, error: reqwest::Error) -> Self {
Self::WrappedReqwestError(url, WrappedReqwestError::from(error)) Self::WrappedReqwestError(url, WrappedReqwestError::from(error))
} }
pub(crate) fn from_reqwest_middleware(url: Url, err: reqwest_middleware::Error) -> Self { /// Create an [`ErrorKind`] from a [`reqwest_middleware::Error`].
pub(crate) fn from_reqwest_middleware(
url: DisplaySafeUrl,
err: reqwest_middleware::Error,
) -> Self {
if let reqwest_middleware::Error::Middleware(ref underlying) = err { if let reqwest_middleware::Error::Middleware(ref underlying) = err {
if let Some(err) = underlying.downcast_ref::<OfflineError>() { if let Some(err) = underlying.downcast_ref::<OfflineError>() {
return Self::Offline(err.url().to_string()); return Self::Offline(err.url().to_string());

View file

@ -10,7 +10,7 @@ use uv_cache_key::cache_digest;
use uv_distribution_filename::DistFilename; use uv_distribution_filename::DistFilename;
use uv_distribution_types::{File, FileLocation, IndexUrl, UrlString}; use uv_distribution_types::{File, FileLocation, IndexUrl, UrlString};
use uv_pypi_types::HashDigests; use uv_pypi_types::HashDigests;
use uv_redacted::redacted_url; use uv_redacted::DisplaySafeUrl;
use uv_small_str::SmallString; use uv_small_str::SmallString;
use crate::cached_client::{CacheControl, CachedClientError}; use crate::cached_client::{CacheControl, CachedClientError};
@ -20,13 +20,13 @@ use crate::{CachedClient, Connectivity, Error, ErrorKind, OwnedArchive};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum FlatIndexError { pub enum FlatIndexError {
#[error("Expected a file URL, but received: {0}")] #[error("Expected a file URL, but received: {0}")]
NonFileUrl(Url), NonFileUrl(DisplaySafeUrl),
#[error("Failed to read `--find-links` directory: {0}")] #[error("Failed to read `--find-links` directory: {0}")]
FindLinksDirectory(PathBuf, #[source] FindLinksDirectoryError), FindLinksDirectory(PathBuf, #[source] FindLinksDirectoryError),
#[error("Failed to read `--find-links` URL: {0}")] #[error("Failed to read `--find-links` URL: {0}")]
FindLinksUrl(Url, #[source] Error), FindLinksUrl(DisplaySafeUrl, #[source] Error),
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -159,7 +159,7 @@ impl<'a> FlatIndexClient<'a> {
/// Read a flat remote index from a `--find-links` URL. /// Read a flat remote index from a `--find-links` URL.
async fn read_from_url( async fn read_from_url(
&self, &self,
url: &Url, url: &DisplaySafeUrl,
flat_index: &IndexUrl, flat_index: &IndexUrl,
) -> Result<FlatIndexEntries, Error> { ) -> Result<FlatIndexEntries, Error> {
let cache_entry = self.cache.entry( let cache_entry = self.cache.entry(
@ -180,7 +180,7 @@ impl<'a> FlatIndexClient<'a> {
.client .client
.uncached() .uncached()
.for_host(url) .for_host(url)
.get(url.clone()) .get(Url::from(url.clone()))
.header("Accept-Encoding", "gzip") .header("Accept-Encoding", "gzip")
.header("Accept", "text/html") .header("Accept", "text/html")
.build() .build()
@ -189,7 +189,7 @@ impl<'a> FlatIndexClient<'a> {
async { async {
// Use the response URL, rather than the request URL, as the base for relative URLs. // Use the response URL, rather than the request URL, as the base for relative URLs.
// This ensures that we handle redirects and other URL transformations correctly. // This ensures that we handle redirects and other URL transformations correctly.
let url = response.url().clone(); let url = DisplaySafeUrl::from(response.url().clone());
let text = response let text = response
.text() .text()
@ -208,7 +208,7 @@ impl<'a> FlatIndexClient<'a> {
Ok(file) => Some(file), Ok(file) => Some(file),
Err(err) => { Err(err) => {
// Ignore files with unparsable version specifiers. // Ignore files with unparsable version specifiers.
warn!("Skipping file in {}: {err}", redacted_url(&url)); warn!("Skipping file in {}: {err}", &url);
None None
} }
} }
@ -246,7 +246,7 @@ impl<'a> FlatIndexClient<'a> {
.collect(); .collect();
Ok(FlatIndexEntries::from_entries(files)) Ok(FlatIndexEntries::from_entries(files))
} }
Err(CachedClientError::Client(err)) if err.is_offline() => { Err(CachedClientError::Client { err, .. }) if err.is_offline() => {
Ok(FlatIndexEntries::offline()) Ok(FlatIndexEntries::offline())
} }
Err(err) => Err(err.into()), Err(err) => Err(err.into()),
@ -294,7 +294,7 @@ impl<'a> FlatIndexClient<'a> {
}; };
// SAFETY: The index path is itself constructed from a URL. // SAFETY: The index path is itself constructed from a URL.
let url = Url::from_file_path(entry.path()).unwrap(); let url = DisplaySafeUrl::from_file_path(entry.path()).unwrap();
let file = File { let file = File {
dist_info_metadata: false, dist_info_metadata: false,
@ -303,7 +303,7 @@ impl<'a> FlatIndexClient<'a> {
requires_python: None, requires_python: None,
size: None, size: None,
upload_time_utc_ms: None, upload_time_utc_ms: None,
url: FileLocation::AbsoluteUrl(UrlString::from(&url)), url: FileLocation::AbsoluteUrl(UrlString::from(url)),
yanked: None, yanked: None,
}; };

View file

@ -8,6 +8,7 @@ use url::Url;
use uv_pep440::VersionSpecifiers; use uv_pep440::VersionSpecifiers;
use uv_pypi_types::{BaseUrl, CoreMetadata, File, Hashes, Yanked}; use uv_pypi_types::{BaseUrl, CoreMetadata, File, Hashes, Yanked};
use uv_pypi_types::{HashError, LenientVersionSpecifiers}; use uv_pypi_types::{HashError, LenientVersionSpecifiers};
use uv_redacted::DisplaySafeUrl;
/// A parsed structure from PyPI "HTML" index format for a single package. /// A parsed structure from PyPI "HTML" index format for a single package.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -27,7 +28,7 @@ impl SimpleHtml {
// Parse the first `<base>` tag, if any, to determine the base URL to which all // Parse the first `<base>` tag, if any, to determine the base URL to which all
// relative URLs should be resolved. The HTML spec requires that the `<base>` tag // relative URLs should be resolved. The HTML spec requires that the `<base>` tag
// appear before other tags with attribute values of URLs. // appear before other tags with attribute values of URLs.
let base = BaseUrl::from( let base = BaseUrl::from(DisplaySafeUrl::from(
dom.nodes() dom.nodes()
.iter() .iter()
.filter_map(|node| node.as_tag()) .filter_map(|node| node.as_tag())
@ -37,7 +38,7 @@ impl SimpleHtml {
.transpose()? .transpose()?
.flatten() .flatten()
.unwrap_or_else(|| url.clone()), .unwrap_or_else(|| url.clone()),
); ));
// Parse each `<a>` tag, to extract the filename, hash, and URL. // Parse each `<a>` tag, to extract the filename, hash, and URL.
let mut files: Vec<File> = dom let mut files: Vec<File> = dom
@ -278,7 +279,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -335,7 +336,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -395,7 +396,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -452,7 +453,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -509,7 +510,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -566,7 +567,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -621,7 +622,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -673,10 +674,10 @@ mod tests {
"; ";
let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap(); let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap();
let result = SimpleHtml::parse(text, &base).unwrap(); let result = SimpleHtml::parse(text, &base).unwrap();
insta::assert_debug_snapshot!(result, @r###" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -694,7 +695,7 @@ mod tests {
), ),
files: [], files: [],
} }
"###); "#);
} }
#[test] #[test]
@ -711,10 +712,10 @@ mod tests {
"#; "#;
let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap(); let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap();
let result = SimpleHtml::parse(text, &base).unwrap(); let result = SimpleHtml::parse(text, &base).unwrap();
insta::assert_debug_snapshot!(result, @r###" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -732,7 +733,7 @@ mod tests {
), ),
files: [], files: [],
} }
"###); "#);
} }
#[test] #[test]
@ -752,7 +753,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -807,7 +808,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -863,7 +864,7 @@ mod tests {
Ok( Ok(
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -920,7 +921,7 @@ mod tests {
Ok( Ok(
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -994,7 +995,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -1076,7 +1077,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -1179,7 +1180,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",
@ -1252,7 +1253,7 @@ mod tests {
insta::assert_debug_snapshot!(result, @r#" insta::assert_debug_snapshot!(result, @r#"
SimpleHtml { SimpleHtml {
base: BaseUrl( base: BaseUrl(
Url { DisplaySafeUrl {
scheme: "https", scheme: "https",
cannot_be_a_base: false, cannot_be_a_base: false,
username: "", username: "",

View file

@ -21,7 +21,6 @@ use crate::rkyvutil::OwnedArchive;
rkyv::Serialize, rkyv::Serialize,
)] )]
#[rkyv(derive(Debug))] #[rkyv(derive(Debug))]
#[allow(clippy::struct_excessive_bools)]
pub struct CacheControl { pub struct CacheControl {
// directives for requests and responses // directives for requests and responses
/// * <https://www.rfc-editor.org/rfc/rfc9111.html#name-max-age> /// * <https://www.rfc-editor.org/rfc/rfc9111.html#name-max-age>

View file

@ -1,6 +1,6 @@
pub use base_client::{ pub use base_client::{
AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware, AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware,
UvRetryableStrategy, is_extended_transient_error, RedirectClientWithMiddleware, RequestBuilder, UvRetryableStrategy, is_extended_transient_error,
}; };
pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy}; pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy};
pub use error::{Error, ErrorKind, WrappedReqwestError}; pub use error::{Error, ErrorKind, WrappedReqwestError};

View file

@ -1,19 +1,19 @@
use http::Extensions; use http::Extensions;
use std::fmt::Debug; use std::fmt::Debug;
use uv_redacted::DisplaySafeUrl;
use reqwest::{Request, Response}; use reqwest::{Request, Response};
use reqwest_middleware::{Middleware, Next}; use reqwest_middleware::{Middleware, Next};
use url::Url;
/// A custom error type for the offline middleware. /// A custom error type for the offline middleware.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct OfflineError { pub(crate) struct OfflineError {
url: Url, url: DisplaySafeUrl,
} }
impl OfflineError { impl OfflineError {
/// Returns the URL that caused the error. /// Returns the URL that caused the error.
pub(crate) fn url(&self) -> &Url { pub(crate) fn url(&self) -> &DisplaySafeUrl {
&self.url &self.url
} }
} }
@ -43,7 +43,7 @@ impl Middleware for OfflineMiddleware {
) -> reqwest_middleware::Result<Response> { ) -> reqwest_middleware::Result<Response> {
Err(reqwest_middleware::Error::Middleware( Err(reqwest_middleware::Error::Middleware(
OfflineError { OfflineError {
url: req.url().clone(), url: DisplaySafeUrl::from(req.url().clone()),
} }
.into(), .into(),
)) ))

View file

@ -10,7 +10,6 @@ use futures::{FutureExt, StreamExt, TryStreamExt};
use http::{HeaderMap, StatusCode}; use http::{HeaderMap, StatusCode};
use itertools::Either; use itertools::Either;
use reqwest::{Proxy, Response}; use reqwest::{Proxy, Response};
use reqwest_middleware::ClientWithMiddleware;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use tokio::sync::{Mutex, Semaphore}; use tokio::sync::{Mutex, Semaphore};
use tracing::{Instrument, debug, info_span, instrument, trace, warn}; use tracing::{Instrument, debug, info_span, instrument, trace, warn};
@ -22,8 +21,8 @@ use uv_configuration::KeyringProviderType;
use uv_configuration::{IndexStrategy, TrustedHost}; use uv_configuration::{IndexStrategy, TrustedHost};
use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename}; use uv_distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
use uv_distribution_types::{ use uv_distribution_types::{
BuiltDist, File, FileLocation, IndexCapabilities, IndexFormat, IndexLocations, BuiltDist, File, IndexCapabilities, IndexFormat, IndexLocations, IndexMetadataRef,
IndexMetadataRef, IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl, IndexUrls, Name, IndexStatusCodeDecision, IndexStatusCodeStrategy, IndexUrl, IndexUrls, Name,
}; };
use uv_metadata::{read_metadata_async_seek, read_metadata_async_stream}; use uv_metadata::{read_metadata_async_seek, read_metadata_async_stream};
use uv_normalize::PackageName; use uv_normalize::PackageName;
@ -31,19 +30,19 @@ use uv_pep440::Version;
use uv_pep508::MarkerEnvironment; use uv_pep508::MarkerEnvironment;
use uv_platform_tags::Platform; use uv_platform_tags::Platform;
use uv_pypi_types::{ResolutionMetadata, SimpleJson}; use uv_pypi_types::{ResolutionMetadata, SimpleJson};
use uv_redacted::redacted_url; use uv_redacted::DisplaySafeUrl;
use uv_small_str::SmallString; use uv_small_str::SmallString;
use uv_torch::TorchStrategy; use uv_torch::TorchStrategy;
use crate::base_client::{BaseClientBuilder, ExtraMiddleware}; use crate::base_client::{BaseClientBuilder, ExtraMiddleware, RedirectPolicy};
use crate::cached_client::CacheControl; use crate::cached_client::CacheControl;
use crate::flat_index::FlatIndexEntry; use crate::flat_index::FlatIndexEntry;
use crate::html::SimpleHtml; use crate::html::SimpleHtml;
use crate::remote_metadata::wheel_metadata_from_remote_zip; use crate::remote_metadata::wheel_metadata_from_remote_zip;
use crate::rkyvutil::OwnedArchive; use crate::rkyvutil::OwnedArchive;
use crate::{ use crate::{
BaseClient, CachedClient, CachedClientError, Error, ErrorKind, FlatIndexClient, BaseClient, CachedClient, Error, ErrorKind, FlatIndexClient, FlatIndexEntries,
FlatIndexEntries, RedirectClientWithMiddleware,
}; };
/// A builder for an [`RegistryClient`]. /// A builder for an [`RegistryClient`].
@ -116,12 +115,25 @@ impl<'a> RegistryClientBuilder<'a> {
self self
} }
pub fn retries_from_env(mut self) -> anyhow::Result<Self> {
self.base_client_builder = self.base_client_builder.retries_from_env()?;
Ok(self)
}
#[must_use] #[must_use]
pub fn native_tls(mut self, native_tls: bool) -> Self { pub fn native_tls(mut self, native_tls: bool) -> Self {
self.base_client_builder = self.base_client_builder.native_tls(native_tls); self.base_client_builder = self.base_client_builder.native_tls(native_tls);
self self
} }
#[must_use]
pub fn built_in_root_certs(mut self, built_in_root_certs: bool) -> Self {
self.base_client_builder = self
.base_client_builder
.built_in_root_certs(built_in_root_certs);
self
}
#[must_use] #[must_use]
pub fn cache(mut self, cache: Cache) -> Self { pub fn cache(mut self, cache: Cache) -> Self {
self.cache = cache; self.cache = cache;
@ -152,9 +164,23 @@ impl<'a> RegistryClientBuilder<'a> {
self self
} }
/// Allows credentials to be propagated on cross-origin redirects.
///
/// WARNING: This should only be available for tests. In production code, propagating credentials
/// during cross-origin redirects can lead to security vulnerabilities including credential
/// leakage to untrusted domains.
#[cfg(test)]
#[must_use]
pub fn allow_cross_origin_credentials(mut self) -> Self {
self.base_client_builder = self.base_client_builder.allow_cross_origin_credentials();
self
}
pub fn build(self) -> RegistryClient { pub fn build(self) -> RegistryClient {
// Build a base client // Build a base client
let builder = self.base_client_builder; let builder = self
.base_client_builder
.redirect(RedirectPolicy::RetriggerMiddleware);
let client = builder.build(); let client = builder.build();
@ -251,12 +277,12 @@ impl RegistryClient {
} }
/// Return the [`BaseClient`] used by this client. /// Return the [`BaseClient`] used by this client.
pub fn uncached_client(&self, url: &Url) -> &ClientWithMiddleware { pub fn uncached_client(&self, url: &DisplaySafeUrl) -> &RedirectClientWithMiddleware {
self.client.uncached().for_host(url) self.client.uncached().for_host(url)
} }
/// Returns `true` if SSL verification is disabled for the given URL. /// Returns `true` if SSL verification is disabled for the given URL.
pub fn disable_ssl(&self, url: &Url) -> bool { pub fn disable_ssl(&self, url: &DisplaySafeUrl) -> bool {
self.client.uncached().disable_ssl(url) self.client.uncached().disable_ssl(url)
} }
@ -485,10 +511,7 @@ impl RegistryClient {
// ref https://github.com/servo/rust-url/issues/333 // ref https://github.com/servo/rust-url/issues/333
.push(""); .push("");
trace!( trace!("Fetching metadata for {package_name} from {url}");
"Fetching metadata for {package_name} from {}",
redacted_url(&url)
);
let cache_entry = self.cache.entry( let cache_entry = self.cache.entry(
CacheBucket::Simple, CacheBucket::Simple,
@ -496,11 +519,17 @@ impl RegistryClient {
format!("{package_name}.rkyv"), format!("{package_name}.rkyv"),
); );
let cache_control = match self.connectivity { let cache_control = match self.connectivity {
Connectivity::Online => CacheControl::from( Connectivity::Online => {
if let Some(header) = self.index_urls.simple_api_cache_control_for(index) {
CacheControl::Override(header)
} else {
CacheControl::from(
self.cache self.cache
.freshness(&cache_entry, Some(package_name), None) .freshness(&cache_entry, Some(package_name), None)
.map_err(ErrorKind::Io)?, .map_err(ErrorKind::Io)?,
), )
}
}
Connectivity::Offline => CacheControl::AllowStale, Connectivity::Offline => CacheControl::AllowStale,
}; };
@ -520,11 +549,11 @@ impl RegistryClient {
match result { match result {
Ok(metadata) => Ok(SimpleMetadataSearchOutcome::Found(metadata)), Ok(metadata) => Ok(SimpleMetadataSearchOutcome::Found(metadata)),
Err(err) => match err.into_kind() { Err(err) => match err.kind() {
// The package could not be found in the remote index. // The package could not be found in the remote index.
ErrorKind::WrappedReqwestError(url, err) => { ErrorKind::WrappedReqwestError(.., reqwest_err) => {
let Some(status_code) = err.status() else { let Some(status_code) = reqwest_err.status() else {
return Err(ErrorKind::WrappedReqwestError(url, err).into()); return Err(err);
}; };
let decision = let decision =
status_code_strategy.handle_status_code(status_code, index, capabilities); status_code_strategy.handle_status_code(status_code, index, capabilities);
@ -533,7 +562,7 @@ impl RegistryClient {
status_code, status_code,
StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN
) { ) {
return Err(ErrorKind::WrappedReqwestError(url, err).into()); return Err(err);
} }
} }
Ok(SimpleMetadataSearchOutcome::from(decision)) Ok(SimpleMetadataSearchOutcome::from(decision))
@ -545,7 +574,7 @@ impl RegistryClient {
// The package could not be found in the local index. // The package could not be found in the local index.
ErrorKind::FileNotFound(_) => Ok(SimpleMetadataSearchOutcome::NotFound), ErrorKind::FileNotFound(_) => Ok(SimpleMetadataSearchOutcome::NotFound),
err => Err(err.into()), _ => Err(err),
}, },
} }
} }
@ -554,14 +583,14 @@ impl RegistryClient {
async fn fetch_remote_index( async fn fetch_remote_index(
&self, &self,
package_name: &PackageName, package_name: &PackageName,
url: &Url, url: &DisplaySafeUrl,
cache_entry: &CacheEntry, cache_entry: &CacheEntry,
cache_control: CacheControl, cache_control: CacheControl<'_>,
) -> Result<OwnedArchive<SimpleMetadata>, Error> { ) -> Result<OwnedArchive<SimpleMetadata>, Error> {
let simple_request = self let simple_request = self
.uncached_client(url) .uncached_client(url)
.get(url.clone()) .get(Url::from(url.clone()))
.header("Accept-Encoding", "gzip") .header("Accept-Encoding", "gzip, deflate, zstd")
.header("Accept", MediaType::accepts()) .header("Accept", MediaType::accepts())
.build() .build()
.map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?; .map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?;
@ -569,7 +598,7 @@ impl RegistryClient {
async { async {
// Use the response URL, rather than the request URL, as the base for relative URLs. // Use the response URL, rather than the request URL, as the base for relative URLs.
// This ensures that we handle redirects and other URL transformations correctly. // This ensures that we handle redirects and other URL transformations correctly.
let url = response.url().clone(); let url = DisplaySafeUrl::from(response.url().clone());
let content_type = response let content_type = response
.headers() .headers()
@ -610,18 +639,16 @@ impl RegistryClient {
.boxed_local() .boxed_local()
.instrument(info_span!("parse_simple_api", package = %package_name)) .instrument(info_span!("parse_simple_api", package = %package_name))
}; };
self.cached_client() let simple = self
.cached_client()
.get_cacheable_with_retry( .get_cacheable_with_retry(
simple_request, simple_request,
cache_entry, cache_entry,
cache_control, cache_control,
parse_simple_response, parse_simple_response,
) )
.await .await?;
.map_err(|err| match err { Ok(simple)
CachedClientError::Client(err) => err,
CachedClientError::Callback(err) => err,
})
} }
/// Fetch the [`SimpleMetadata`] from a local file, using a PEP 503-compatible directory /// Fetch the [`SimpleMetadata`] from a local file, using a PEP 503-compatible directory
@ -629,7 +656,7 @@ impl RegistryClient {
async fn fetch_local_index( async fn fetch_local_index(
&self, &self,
package_name: &PackageName, package_name: &PackageName,
url: &Url, url: &DisplaySafeUrl,
) -> Result<OwnedArchive<SimpleMetadata>, Error> { ) -> Result<OwnedArchive<SimpleMetadata>, Error> {
let path = url let path = url
.to_file_path() .to_file_path()
@ -669,35 +696,19 @@ impl RegistryClient {
/// A local file path. /// A local file path.
Path(PathBuf), Path(PathBuf),
/// A remote URL. /// A remote URL.
Url(Url), Url(DisplaySafeUrl),
} }
let wheel = wheels.best_wheel(); let wheel = wheels.best_wheel();
let location = match &wheel.file.url { let url = wheel.file.url.to_url().map_err(ErrorKind::InvalidUrl)?;
FileLocation::RelativeUrl(base, url) => { let location = if url.scheme() == "file" {
let url = uv_pypi_types::base_url_join_relative(base, url)
.map_err(ErrorKind::JoinRelativeUrl)?;
if url.scheme() == "file" {
let path = url let path = url
.to_file_path() .to_file_path()
.map_err(|()| ErrorKind::NonFileUrl(url.clone()))?; .map_err(|()| ErrorKind::NonFileUrl(url.clone()))?;
WheelLocation::Path(path) WheelLocation::Path(path)
} else { } else {
WheelLocation::Url(url) WheelLocation::Url(url)
}
}
FileLocation::AbsoluteUrl(url) => {
let url = url.to_url().map_err(ErrorKind::InvalidUrl)?;
if url.scheme() == "file" {
let path = url
.to_file_path()
.map_err(|()| ErrorKind::NonFileUrl(url.clone()))?;
WheelLocation::Path(path)
} else {
WheelLocation::Url(url)
}
}
}; };
match location { match location {
@ -770,14 +781,15 @@ impl RegistryClient {
&self, &self,
index: &IndexUrl, index: &IndexUrl,
file: &File, file: &File,
url: &Url, url: &DisplaySafeUrl,
capabilities: &IndexCapabilities, capabilities: &IndexCapabilities,
) -> Result<ResolutionMetadata, Error> { ) -> Result<ResolutionMetadata, Error> {
// If the metadata file is available at its own url (PEP 658), download it from there. // If the metadata file is available at its own url (PEP 658), download it from there.
let filename = WheelFilename::from_str(&file.filename).map_err(ErrorKind::WheelFilename)?; let filename = WheelFilename::from_str(&file.filename).map_err(ErrorKind::WheelFilename)?;
if file.dist_info_metadata { if file.dist_info_metadata {
let mut url = url.clone(); let mut url = url.clone();
url.set_path(&format!("{}.metadata", url.path())); let path = format!("{}.metadata", url.path());
url.set_path(&path);
let cache_entry = self.cache.entry( let cache_entry = self.cache.entry(
CacheBucket::Wheels, CacheBucket::Wheels,
@ -785,11 +797,17 @@ impl RegistryClient {
format!("{}.msgpack", filename.cache_key()), format!("{}.msgpack", filename.cache_key()),
); );
let cache_control = match self.connectivity { let cache_control = match self.connectivity {
Connectivity::Online => CacheControl::from( Connectivity::Online => {
if let Some(header) = self.index_urls.artifact_cache_control_for(index) {
CacheControl::Override(header)
} else {
CacheControl::from(
self.cache self.cache
.freshness(&cache_entry, Some(&filename.name), None) .freshness(&cache_entry, Some(&filename.name), None)
.map_err(ErrorKind::Io)?, .map_err(ErrorKind::Io)?,
), )
}
}
Connectivity::Offline => CacheControl::AllowStale, Connectivity::Offline => CacheControl::AllowStale,
}; };
@ -818,7 +836,7 @@ impl RegistryClient {
}; };
let req = self let req = self
.uncached_client(&url) .uncached_client(&url)
.get(url.clone()) .get(Url::from(url.clone()))
.build() .build()
.map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?; .map_err(|err| ErrorKind::from_reqwest(url.clone(), err))?;
Ok(self Ok(self
@ -844,7 +862,7 @@ impl RegistryClient {
async fn wheel_metadata_no_pep658<'data>( async fn wheel_metadata_no_pep658<'data>(
&self, &self,
filename: &'data WheelFilename, filename: &'data WheelFilename,
url: &'data Url, url: &'data DisplaySafeUrl,
index: Option<&'data IndexUrl>, index: Option<&'data IndexUrl>,
cache_shard: WheelCache<'data>, cache_shard: WheelCache<'data>,
capabilities: &'data IndexCapabilities, capabilities: &'data IndexCapabilities,
@ -855,11 +873,25 @@ impl RegistryClient {
format!("{}.msgpack", filename.cache_key()), format!("{}.msgpack", filename.cache_key()),
); );
let cache_control = match self.connectivity { let cache_control = match self.connectivity {
Connectivity::Online => CacheControl::from( Connectivity::Online => {
if let Some(index) = index {
if let Some(header) = self.index_urls.artifact_cache_control_for(index) {
CacheControl::Override(header)
} else {
CacheControl::from(
self.cache self.cache
.freshness(&cache_entry, Some(&filename.name), None) .freshness(&cache_entry, Some(&filename.name), None)
.map_err(ErrorKind::Io)?, .map_err(ErrorKind::Io)?,
), )
}
} else {
CacheControl::from(
self.cache
.freshness(&cache_entry, Some(&filename.name), None)
.map_err(ErrorKind::Io)?,
)
}
}
Connectivity::Offline => CacheControl::AllowStale, Connectivity::Offline => CacheControl::AllowStale,
}; };
@ -874,7 +906,7 @@ impl RegistryClient {
if index.is_none_or(|index| capabilities.supports_range_requests(index)) { if index.is_none_or(|index| capabilities.supports_range_requests(index)) {
let req = self let req = self
.uncached_client(url) .uncached_client(url)
.head(url.clone()) .head(Url::from(url.clone()))
.header( .header(
"accept-encoding", "accept-encoding",
http::HeaderValue::from_static("identity"), http::HeaderValue::from_static("identity"),
@ -895,22 +927,20 @@ impl RegistryClient {
let mut reader = AsyncHttpRangeReader::from_head_response( let mut reader = AsyncHttpRangeReader::from_head_response(
self.uncached_client(url).clone(), self.uncached_client(url).clone(),
response, response,
url.clone(), Url::from(url.clone()),
headers.clone(), headers.clone(),
) )
.await .await
.map_err(|err| ErrorKind::AsyncHttpRangeReader(url.clone(), err))?; .map_err(|err| ErrorKind::AsyncHttpRangeReader(url.clone(), err))?;
trace!("Getting metadata for {filename} by range request"); trace!("Getting metadata for {filename} by range request");
let text = wheel_metadata_from_remote_zip(filename, url, &mut reader).await?; let text = wheel_metadata_from_remote_zip(filename, url, &mut reader).await?;
let metadata =
ResolutionMetadata::parse_metadata(text.as_bytes()).map_err(|err| { ResolutionMetadata::parse_metadata(text.as_bytes()).map_err(|err| {
Error::from(ErrorKind::MetadataParseError( Error::from(ErrorKind::MetadataParseError(
filename.clone(), filename.clone(),
url.to_string(), url.to_string(),
Box::new(err), Box::new(err),
)) ))
})?; })
Ok::<ResolutionMetadata, CachedClientError<Error>>(metadata)
} }
.boxed_local() .boxed_local()
.instrument(info_span!("read_metadata_range_request", wheel = %filename)) .instrument(info_span!("read_metadata_range_request", wheel = %filename))
@ -949,7 +979,7 @@ impl RegistryClient {
// Create a request to stream the file. // Create a request to stream the file.
let req = self let req = self
.uncached_client(url) .uncached_client(url)
.get(url.clone()) .get(Url::from(url.clone()))
.header( .header(
// `reqwest` defaults to accepting compressed responses. // `reqwest` defaults to accepting compressed responses.
// Specify identity encoding to get consistent .whl downloading // Specify identity encoding to get consistent .whl downloading
@ -1141,7 +1171,11 @@ impl SimpleMetadata {
} }
/// Read the [`SimpleMetadata`] from an HTML index. /// Read the [`SimpleMetadata`] from an HTML index.
fn from_html(text: &str, package_name: &PackageName, url: &Url) -> Result<Self, Error> { fn from_html(
text: &str,
package_name: &PackageName,
url: &DisplaySafeUrl,
) -> Result<Self, Error> {
let SimpleHtml { base, files } = let SimpleHtml { base, files } =
SimpleHtml::parse(text, url).map_err(|err| Error::from_html_err(err, url.clone()))?; SimpleHtml::parse(text, url).map_err(|err| Error::from_html_err(err, url.clone()))?;
@ -1221,12 +1255,191 @@ mod tests {
use std::str::FromStr; use std::str::FromStr;
use url::Url; use url::Url;
use uv_normalize::PackageName; use uv_normalize::PackageName;
use uv_pypi_types::{JoinRelativeError, SimpleJson}; use uv_pypi_types::SimpleJson;
use uv_redacted::DisplaySafeUrl;
use crate::{SimpleMetadata, SimpleMetadatum, html::SimpleHtml}; use crate::{SimpleMetadata, SimpleMetadatum, html::SimpleHtml};
use crate::RegistryClientBuilder;
use uv_cache::Cache;
use uv_distribution_types::{FileLocation, ToUrlError};
use uv_small_str::SmallString;
use wiremock::matchers::{basic_auth, method, path_regex};
use wiremock::{Mock, MockServer, ResponseTemplate};
type Error = Box<dyn std::error::Error>;
async fn start_test_server(username: &'static str, password: &'static str) -> MockServer {
let server = MockServer::start().await;
Mock::given(method("GET"))
.and(basic_auth(username, password))
.respond_with(ResponseTemplate::new(200))
.mount(&server)
.await;
Mock::given(method("GET"))
.respond_with(ResponseTemplate::new(401))
.mount(&server)
.await;
server
}
#[tokio::test]
async fn test_redirect_to_server_with_credentials() -> Result<(), Error> {
let username = "user";
let password = "password";
let auth_server = start_test_server(username, password).await;
let auth_base_url = DisplaySafeUrl::parse(&auth_server.uri())?;
let redirect_server = MockServer::start().await;
// Configure the redirect server to respond with a 302 to the auth server
Mock::given(method("GET"))
.respond_with(
ResponseTemplate::new(302).insert_header("Location", format!("{auth_base_url}")),
)
.mount(&redirect_server)
.await;
let redirect_server_url = DisplaySafeUrl::parse(&redirect_server.uri())?;
let cache = Cache::temp()?;
let registry_client = RegistryClientBuilder::new(cache)
.allow_cross_origin_credentials()
.build();
let client = registry_client.cached_client().uncached();
assert_eq!(
client
.for_host(&redirect_server_url)
.get(redirect_server.uri())
.send()
.await?
.status(),
401,
"Requests should fail if credentials are missing"
);
let mut url = redirect_server_url.clone();
let _ = url.set_username(username);
let _ = url.set_password(Some(password));
assert_eq!(
client
.for_host(&redirect_server_url)
.get(Url::from(url))
.send()
.await?
.status(),
200,
"Requests should succeed if credentials are present"
);
Ok(())
}
#[tokio::test]
async fn test_redirect_root_relative_url() -> Result<(), Error> {
let username = "user";
let password = "password";
let redirect_server = MockServer::start().await;
// Configure the redirect server to respond with a 307 with a relative URL.
Mock::given(method("GET"))
.and(path_regex("/foo/"))
.respond_with(
ResponseTemplate::new(307).insert_header("Location", "/bar/baz/".to_string()),
)
.mount(&redirect_server)
.await;
Mock::given(method("GET"))
.and(path_regex("/bar/baz/"))
.and(basic_auth(username, password))
.respond_with(ResponseTemplate::new(200))
.mount(&redirect_server)
.await;
let redirect_server_url = DisplaySafeUrl::parse(&redirect_server.uri())?.join("foo/")?;
let cache = Cache::temp()?;
let registry_client = RegistryClientBuilder::new(cache)
.allow_cross_origin_credentials()
.build();
let client = registry_client.cached_client().uncached();
let mut url = redirect_server_url.clone();
let _ = url.set_username(username);
let _ = url.set_password(Some(password));
assert_eq!(
client
.for_host(&url)
.get(Url::from(url))
.send()
.await?
.status(),
200,
"Requests should succeed for relative URL"
);
Ok(())
}
#[tokio::test]
async fn test_redirect_relative_url() -> Result<(), Error> {
let username = "user";
let password = "password";
let redirect_server = MockServer::start().await;
// Configure the redirect server to respond with a 307 with a relative URL.
Mock::given(method("GET"))
.and(path_regex("/foo/bar/baz/"))
.and(basic_auth(username, password))
.respond_with(ResponseTemplate::new(200))
.mount(&redirect_server)
.await;
Mock::given(method("GET"))
.and(path_regex("/foo/"))
.and(basic_auth(username, password))
.respond_with(
ResponseTemplate::new(307).insert_header("Location", "bar/baz/".to_string()),
)
.mount(&redirect_server)
.await;
let cache = Cache::temp()?;
let registry_client = RegistryClientBuilder::new(cache)
.allow_cross_origin_credentials()
.build();
let client = registry_client.cached_client().uncached();
let redirect_server_url = DisplaySafeUrl::parse(&redirect_server.uri())?.join("foo/")?;
let mut url = redirect_server_url.clone();
let _ = url.set_username(username);
let _ = url.set_password(Some(password));
assert_eq!(
client
.for_host(&url)
.get(Url::from(url))
.send()
.await?
.status(),
200,
"Requests should succeed for relative URL"
);
Ok(())
}
#[test] #[test]
fn ignore_failing_files() { fn ignore_failing_files() {
// 1.7.7 has an invalid requires-python field (double comma), 1.7.8 is valid // 1.7.7 has an invalid requires-python field (double comma), 1.7.8 is valid
@ -1263,7 +1476,7 @@ mod tests {
} }
"#; "#;
let data: SimpleJson = serde_json::from_str(response).unwrap(); let data: SimpleJson = serde_json::from_str(response).unwrap();
let base = Url::parse("https://pypi.org/simple/pyflyby/").unwrap(); let base = DisplaySafeUrl::parse("https://pypi.org/simple/pyflyby/").unwrap();
let simple_metadata = SimpleMetadata::from_files( let simple_metadata = SimpleMetadata::from_files(
data.files, data.files,
&PackageName::from_str("pyflyby").unwrap(), &PackageName::from_str("pyflyby").unwrap(),
@ -1280,7 +1493,7 @@ mod tests {
/// ///
/// See: <https://github.com/astral-sh/uv/issues/1388> /// See: <https://github.com/astral-sh/uv/issues/1388>
#[test] #[test]
fn relative_urls_code_artifact() -> Result<(), JoinRelativeError> { fn relative_urls_code_artifact() -> Result<(), ToUrlError> {
let text = r#" let text = r#"
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -1300,16 +1513,20 @@ mod tests {
"#; "#;
// Note the lack of a trailing `/` here is important for coverage of url-join behavior // Note the lack of a trailing `/` here is important for coverage of url-join behavior
let base = Url::parse("https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/flask") let base = DisplaySafeUrl::parse("https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/flask")
.unwrap(); .unwrap();
let SimpleHtml { base, files } = SimpleHtml::parse(text, &base).unwrap(); let SimpleHtml { base, files } = SimpleHtml::parse(text, &base).unwrap();
let base = SmallString::from(base.as_str());
// Test parsing of the file urls // Test parsing of the file urls
let urls = files let urls = files
.into_iter()
.map(|file| FileLocation::new(file.url, &base).to_url())
.collect::<Result<Vec<_>, _>>()?;
let urls = urls
.iter() .iter()
.map(|file| uv_pypi_types::base_url_join_relative(base.as_url().as_str(), &file.url)) .map(DisplaySafeUrl::to_string)
.collect::<Result<Vec<_>, JoinRelativeError>>()?; .collect::<Vec<_>>();
let urls = urls.iter().map(Url::as_str).collect::<Vec<_>>();
insta::assert_debug_snapshot!(urls, @r#" insta::assert_debug_snapshot!(urls, @r#"
[ [
"https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/0.1/Flask-0.1.tar.gz", "https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/0.1/Flask-0.1.tar.gz",

View file

@ -1,13 +1,13 @@
use std::str::FromStr; use std::str::FromStr;
use anyhow::Result; use anyhow::Result;
use url::Url;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClientBuilder; use uv_client::RegistryClientBuilder;
use uv_distribution_filename::WheelFilename; use uv_distribution_filename::WheelFilename;
use uv_distribution_types::{BuiltDist, DirectUrlBuiltDist, IndexCapabilities}; use uv_distribution_types::{BuiltDist, DirectUrlBuiltDist, IndexCapabilities};
use uv_pep508::VerbatimUrl; use uv_pep508::VerbatimUrl;
use uv_redacted::DisplaySafeUrl;
#[tokio::test] #[tokio::test]
async fn remote_metadata_with_and_without_cache() -> Result<()> { async fn remote_metadata_with_and_without_cache() -> Result<()> {
@ -21,7 +21,7 @@ async fn remote_metadata_with_and_without_cache() -> Result<()> {
let filename = WheelFilename::from_str(url.rsplit_once('/').unwrap().1)?; let filename = WheelFilename::from_str(url.rsplit_once('/').unwrap().1)?;
let dist = BuiltDist::DirectUrl(DirectUrlBuiltDist { let dist = BuiltDist::DirectUrl(DirectUrlBuiltDist {
filename, filename,
location: Box::new(Url::parse(url).unwrap()), location: Box::new(DisplaySafeUrl::parse(url).unwrap()),
url: VerbatimUrl::from_str(url).unwrap(), url: VerbatimUrl::from_str(url).unwrap(),
}); });
let capabilities = IndexCapabilities::default(); let capabilities = IndexCapabilities::default();

View file

@ -16,6 +16,7 @@ use uv_client::LineHaul;
use uv_client::RegistryClientBuilder; use uv_client::RegistryClientBuilder;
use uv_pep508::{MarkerEnvironment, MarkerEnvironmentBuilder}; use uv_pep508::{MarkerEnvironment, MarkerEnvironmentBuilder};
use uv_platform_tags::{Arch, Os, Platform}; use uv_platform_tags::{Arch, Os, Platform};
use uv_redacted::DisplaySafeUrl;
use uv_version::version; use uv_version::version;
#[tokio::test] #[tokio::test]
@ -54,12 +55,12 @@ async fn test_user_agent_has_version() -> Result<()> {
let client = RegistryClientBuilder::new(cache).build(); let client = RegistryClientBuilder::new(cache).build();
// Send request to our dummy server // Send request to our dummy server
let url = Url::from_str(&format!("http://{addr}"))?; let url = DisplaySafeUrl::from_str(&format!("http://{addr}"))?;
let res = client let res = client
.cached_client() .cached_client()
.uncached() .uncached()
.for_host(&url) .for_host(&url)
.get(url) .get(Url::from(url))
.send() .send()
.await?; .await?;
@ -151,12 +152,12 @@ async fn test_user_agent_has_linehaul() -> Result<()> {
let client = builder.build(); let client = builder.build();
// Send request to our dummy server // Send request to our dummy server
let url = Url::from_str(&format!("http://{addr}"))?; let url = DisplaySafeUrl::from_str(&format!("http://{addr}"))?;
let res = client let res = client
.cached_client() .cached_client()
.uncached() .uncached()
.for_host(&url) .for_host(&url)
.get(url) .get(Url::from(url))
.send() .send()
.await?; .await?;

View file

@ -27,7 +27,9 @@ uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true, features = ["schemars"] } uv-pep508 = { workspace = true, features = ["schemars"] }
uv-platform-tags = { workspace = true } uv-platform-tags = { workspace = true }
uv-static = { workspace = true } uv-static = { workspace = true }
uv-warnings = { workspace = true }
bitflags = { workspace = true }
clap = { workspace = true, features = ["derive"], optional = true } clap = { workspace = true, features = ["derive"], optional = true }
either = { workspace = true } either = { workspace = true }
fs-err = { workspace = true } fs-err = { workspace = true }

View file

@ -4,7 +4,7 @@ use uv_pep508::PackageName;
use crate::{PackageNameSpecifier, PackageNameSpecifiers}; use crate::{PackageNameSpecifier, PackageNameSpecifiers};
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub enum BuildKind { pub enum BuildKind {
/// A PEP 517 wheel build. /// A PEP 517 wheel build.
#[default] #[default]

View file

@ -3,6 +3,7 @@ use std::{
str::FromStr, str::FromStr,
}; };
use uv_cache_key::CacheKeyHasher; use uv_cache_key::CacheKeyHasher;
use uv_normalize::PackageName;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ConfigSettingEntry { pub struct ConfigSettingEntry {
@ -28,6 +29,32 @@ impl FromStr for ConfigSettingEntry {
} }
} }
#[derive(Debug, Clone)]
pub struct ConfigSettingPackageEntry {
/// The package name to apply the setting to.
package: PackageName,
/// The config setting entry.
setting: ConfigSettingEntry,
}
impl FromStr for ConfigSettingPackageEntry {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let Some((package_str, config_str)) = s.split_once(':') else {
return Err(format!(
"Invalid config setting: {s} (expected `PACKAGE:KEY=VALUE`)"
));
};
let package = PackageName::from_str(package_str.trim())
.map_err(|e| format!("Invalid package name: {e}"))?;
let setting = ConfigSettingEntry::from_str(config_str)?;
Ok(Self { package, setting })
}
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema), schemars(untagged))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema), schemars(untagged))]
enum ConfigSettingValue { enum ConfigSettingValue {
@ -212,6 +239,111 @@ impl<'de> serde::Deserialize<'de> for ConfigSettings {
} }
} }
/// Settings to pass to PEP 517 build backends on a per-package basis.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PackageConfigSettings(BTreeMap<PackageName, ConfigSettings>);
impl FromIterator<ConfigSettingPackageEntry> for PackageConfigSettings {
fn from_iter<T: IntoIterator<Item = ConfigSettingPackageEntry>>(iter: T) -> Self {
let mut package_configs: BTreeMap<PackageName, Vec<ConfigSettingEntry>> = BTreeMap::new();
for entry in iter {
package_configs
.entry(entry.package)
.or_default()
.push(entry.setting);
}
let configs = package_configs
.into_iter()
.map(|(package, entries)| (package, entries.into_iter().collect()))
.collect();
Self(configs)
}
}
impl PackageConfigSettings {
/// Returns the config settings for a specific package, if any.
pub fn get(&self, package: &PackageName) -> Option<&ConfigSettings> {
self.0.get(package)
}
/// Returns `true` if there are no package-specific settings.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// Merge two sets of package config settings, with the values in `self` taking precedence.
#[must_use]
pub fn merge(mut self, other: PackageConfigSettings) -> PackageConfigSettings {
for (package, settings) in other.0 {
match self.0.entry(package) {
Entry::Vacant(vacant) => {
vacant.insert(settings);
}
Entry::Occupied(mut occupied) => {
let merged = occupied.get().clone().merge(settings);
occupied.insert(merged);
}
}
}
self
}
}
impl uv_cache_key::CacheKey for PackageConfigSettings {
fn cache_key(&self, state: &mut CacheKeyHasher) {
for (package, settings) in &self.0 {
package.to_string().cache_key(state);
settings.cache_key(state);
}
}
}
impl serde::Serialize for PackageConfigSettings {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(self.0.len()))?;
for (key, value) in &self.0 {
map.serialize_entry(&key.to_string(), value)?;
}
map.end()
}
}
impl<'de> serde::Deserialize<'de> for PackageConfigSettings {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = PackageConfigSettings;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a map from package name to config settings")
}
fn visit_map<A: serde::de::MapAccess<'de>>(
self,
mut map: A,
) -> Result<Self::Value, A::Error> {
let mut config = BTreeMap::default();
while let Some((key, value)) = map.next_entry::<String, ConfigSettings>()? {
let package = PackageName::from_str(&key).map_err(|e| {
serde::de::Error::custom(format!("Invalid package name: {e}"))
})?;
config.insert(package, value);
}
Ok(PackageConfigSettings(config))
}
}
deserializer.deserialize_map(Visitor)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -291,4 +423,56 @@ mod tests {
); );
assert_eq!(settings.escape_for_python(), r#"{"key":"val\\1 {}value"}"#); assert_eq!(settings.escape_for_python(), r#"{"key":"val\\1 {}value"}"#);
} }
#[test]
fn parse_config_setting_package_entry() {
// Test valid parsing
let entry = ConfigSettingPackageEntry::from_str("numpy:editable_mode=compat").unwrap();
assert_eq!(entry.package.as_ref(), "numpy");
assert_eq!(entry.setting.key, "editable_mode");
assert_eq!(entry.setting.value, "compat");
// Test with package name containing hyphens
let entry = ConfigSettingPackageEntry::from_str("my-package:some_key=value").unwrap();
assert_eq!(entry.package.as_ref(), "my-package");
assert_eq!(entry.setting.key, "some_key");
assert_eq!(entry.setting.value, "value");
// Test with spaces around values
let entry = ConfigSettingPackageEntry::from_str(" numpy : key = value ").unwrap();
assert_eq!(entry.package.as_ref(), "numpy");
assert_eq!(entry.setting.key, "key");
assert_eq!(entry.setting.value, "value");
}
#[test]
fn collect_config_settings_package() {
let settings: PackageConfigSettings = vec![
ConfigSettingPackageEntry::from_str("numpy:editable_mode=compat").unwrap(),
ConfigSettingPackageEntry::from_str("numpy:another_key=value").unwrap(),
ConfigSettingPackageEntry::from_str("scipy:build_option=fast").unwrap(),
]
.into_iter()
.collect();
let numpy_settings = settings
.get(&PackageName::from_str("numpy").unwrap())
.unwrap();
assert_eq!(
numpy_settings.0.get("editable_mode"),
Some(&ConfigSettingValue::String("compat".to_string()))
);
assert_eq!(
numpy_settings.0.get("another_key"),
Some(&ConfigSettingValue::String("value".to_string()))
);
let scipy_settings = settings
.get(&PackageName::from_str("scipy").unwrap())
.unwrap();
assert_eq!(
scipy_settings.0.get("build_option"),
Some(&ConfigSettingValue::String("fast".to_string()))
);
}
} }

View file

@ -186,6 +186,18 @@ impl DependencyGroupsInner {
self.include.names().chain(&self.exclude) self.include.names().chain(&self.exclude)
} }
/// Returns an iterator over all groups that are included in the specification,
/// assuming `all_names` is an iterator over all groups.
pub fn group_names<'a, Names>(
&'a self,
all_names: Names,
) -> impl Iterator<Item = &'a GroupName> + 'a
where
Names: Iterator<Item = &'a GroupName> + 'a,
{
all_names.filter(move |name| self.contains(name))
}
/// Iterate over all groups the user explicitly asked for on the CLI /// Iterate over all groups the user explicitly asked for on the CLI
pub fn explicit_names(&self) -> impl Iterator<Item = &GroupName> { pub fn explicit_names(&self) -> impl Iterator<Item = &GroupName> {
let DependencyGroupsHistory { let DependencyGroupsHistory {
@ -295,6 +307,15 @@ pub struct DependencyGroupsWithDefaults {
} }
impl DependencyGroupsWithDefaults { impl DependencyGroupsWithDefaults {
/// Do not enable any groups
///
/// Many places in the code need to know what dependency-groups are active,
/// but various commands or subsystems never enable any dependency-groups,
/// in which case they want this.
pub fn none() -> Self {
DependencyGroups::default().with_defaults(DefaultGroups::default())
}
/// Returns `true` if the specification was enabled, and *only* because it was a default /// Returns `true` if the specification was enabled, and *only* because it was a default
pub fn contains_because_default(&self, group: &GroupName) -> bool { pub fn contains_because_default(&self, group: &GroupName) -> bool {
self.cur.contains(group) && !self.prev.contains(group) self.cur.contains(group) && !self.prev.contains(group)

View file

@ -155,7 +155,8 @@ impl ExtrasSpecificationInner {
self.include.names().chain(&self.exclude) self.include.names().chain(&self.exclude)
} }
/// Returns `true` if the specification includes the given extra. /// Returns an iterator over all extras that are included in the specification,
/// assuming `all_names` is an iterator over all extras.
pub fn extra_names<'a, Names>( pub fn extra_names<'a, Names>(
&'a self, &'a self,
all_names: Names, all_names: Names,
@ -263,6 +264,14 @@ pub struct ExtrasSpecificationWithDefaults {
} }
impl ExtrasSpecificationWithDefaults { impl ExtrasSpecificationWithDefaults {
/// Do not enable any extras
///
/// Many places in the code need to know what extras are active,
/// but various commands or subsystems never enable any extras,
/// in which case they want this.
pub fn none() -> Self {
ExtrasSpecification::default().with_defaults(DefaultExtras::default())
}
/// Returns `true` if the specification was enabled, and *only* because it was a default /// Returns `true` if the specification was enabled, and *only* because it was a default
pub fn contains_because_default(&self, extra: &ExtraName) -> bool { pub fn contains_because_default(&self, extra: &ExtraName) -> bool {
self.cur.contains(extra) && !self.prev.contains(extra) self.cur.contains(extra) && !self.prev.contains(extra)

View file

@ -1,3 +1,5 @@
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::str::FromStr; use std::str::FromStr;
use uv_pep508::PackageName; use uv_pep508::PackageName;
@ -63,28 +65,16 @@ impl<'de> serde::Deserialize<'de> for PackageNameSpecifier {
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
impl schemars::JsonSchema for PackageNameSpecifier { impl schemars::JsonSchema for PackageNameSpecifier {
fn schema_name() -> String { fn schema_name() -> Cow<'static, str> {
"PackageNameSpecifier".to_string() Cow::Borrowed("PackageNameSpecifier")
} }
fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { fn json_schema(_gen: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
schemars::schema::SchemaObject { schemars::json_schema!({
instance_type: Some(schemars::schema::InstanceType::String.into()), "type": "string",
string: Some(Box::new(schemars::schema::StringValidation { "pattern": r"^(:none:|:all:|([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]))$",
// See: https://packaging.python.org/en/latest/specifications/name-normalization/#name-format "description": "The name of a package, or `:all:` or `:none:` to select or omit all packages, respectively.",
pattern: Some( })
r"^(:none:|:all:|([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]))$"
.to_string(),
),
..schemars::schema::StringValidation::default()
})),
metadata: Some(Box::new(schemars::schema::Metadata {
description: Some("The name of a package, or `:all:` or `:none:` to select or omit all packages, respectively.".to_string()),
..schemars::schema::Metadata::default()
})),
..schemars::schema::SchemaObject::default()
}
.into()
} }
} }

View file

@ -1,37 +1,250 @@
use std::fmt::{Display, Formatter}; use std::{
fmt::{Display, Formatter},
str::FromStr,
};
use thiserror::Error;
use uv_warnings::warn_user_once;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct PreviewFeatures: u32 {
const PYTHON_INSTALL_DEFAULT = 1 << 0;
const PYTHON_UPGRADE = 1 << 1;
const JSON_OUTPUT = 1 << 2;
const PYLOCK = 1 << 3;
const ADD_BOUNDS = 1 << 4;
const EXTRA_BUILD_DEPENDENCIES = 1 << 5;
}
}
impl PreviewFeatures {
/// Returns the string representation of a single preview feature flag.
///
/// Panics if given a combination of flags.
fn flag_as_str(self) -> &'static str {
match self {
Self::PYTHON_INSTALL_DEFAULT => "python-install-default",
Self::PYTHON_UPGRADE => "python-upgrade",
Self::JSON_OUTPUT => "json-output",
Self::PYLOCK => "pylock",
Self::ADD_BOUNDS => "add-bounds",
Self::EXTRA_BUILD_DEPENDENCIES => "extra-build-dependencies",
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
}
}
}
impl Display for PreviewFeatures {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_empty() {
write!(f, "none")
} else {
let features: Vec<&str> = self.iter().map(PreviewFeatures::flag_as_str).collect();
write!(f, "{}", features.join(","))
}
}
}
#[derive(Debug, Error, Clone)]
pub enum PreviewFeaturesParseError {
#[error("Empty string in preview features: {0}")]
Empty(String),
}
impl FromStr for PreviewFeatures {
type Err = PreviewFeaturesParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut flags = PreviewFeatures::empty();
for part in s.split(',') {
let part = part.trim();
if part.is_empty() {
return Err(PreviewFeaturesParseError::Empty(
"Empty string in preview features".to_string(),
));
}
let flag = match part {
"python-install-default" => Self::PYTHON_INSTALL_DEFAULT,
"python-upgrade" => Self::PYTHON_UPGRADE,
"json-output" => Self::JSON_OUTPUT,
"pylock" => Self::PYLOCK,
"add-bounds" => Self::ADD_BOUNDS,
"extra-build-dependencies" => Self::EXTRA_BUILD_DEPENDENCIES,
_ => {
warn_user_once!("Unknown preview feature: `{part}`");
continue;
}
};
flags |= flag;
}
Ok(flags)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PreviewMode { pub struct Preview {
#[default] flags: PreviewFeatures,
Disabled,
Enabled,
} }
impl PreviewMode { impl Preview {
pub fn is_enabled(&self) -> bool { pub fn new(flags: PreviewFeatures) -> Self {
matches!(self, Self::Enabled) Self { flags }
} }
pub fn is_disabled(&self) -> bool { pub fn all() -> Self {
matches!(self, Self::Disabled) Self::new(PreviewFeatures::all())
}
pub fn from_args(
preview: bool,
no_preview: bool,
preview_features: &[PreviewFeatures],
) -> Self {
if no_preview {
return Self::default();
}
if preview {
return Self::all();
}
let mut flags = PreviewFeatures::empty();
for features in preview_features {
flags |= *features;
}
Self { flags }
}
pub fn is_enabled(&self, flag: PreviewFeatures) -> bool {
self.flags.contains(flag)
} }
} }
impl From<bool> for PreviewMode { impl Display for Preview {
fn from(version: bool) -> Self {
if version {
PreviewMode::Enabled
} else {
PreviewMode::Disabled
}
}
}
impl Display for PreviewMode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { if self.flags.is_empty() {
Self::Disabled => write!(f, "disabled"), write!(f, "disabled")
Self::Enabled => write!(f, "enabled"), } else if self.flags == PreviewFeatures::all() {
write!(f, "enabled")
} else {
write!(f, "{}", self.flags)
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_preview_features_from_str() {
// Test single feature
let features = PreviewFeatures::from_str("python-install-default").unwrap();
assert_eq!(features, PreviewFeatures::PYTHON_INSTALL_DEFAULT);
// Test multiple features
let features = PreviewFeatures::from_str("python-upgrade,json-output").unwrap();
assert!(features.contains(PreviewFeatures::PYTHON_UPGRADE));
assert!(features.contains(PreviewFeatures::JSON_OUTPUT));
assert!(!features.contains(PreviewFeatures::PYLOCK));
// Test with whitespace
let features = PreviewFeatures::from_str("pylock , add-bounds").unwrap();
assert!(features.contains(PreviewFeatures::PYLOCK));
assert!(features.contains(PreviewFeatures::ADD_BOUNDS));
// Test empty string error
assert!(PreviewFeatures::from_str("").is_err());
assert!(PreviewFeatures::from_str("pylock,").is_err());
assert!(PreviewFeatures::from_str(",pylock").is_err());
// Test unknown feature (should be ignored with warning)
let features = PreviewFeatures::from_str("unknown-feature,pylock").unwrap();
assert!(features.contains(PreviewFeatures::PYLOCK));
assert_eq!(features.bits().count_ones(), 1);
}
#[test]
fn test_preview_features_display() {
// Test empty
let features = PreviewFeatures::empty();
assert_eq!(features.to_string(), "none");
// Test single feature
let features = PreviewFeatures::PYTHON_INSTALL_DEFAULT;
assert_eq!(features.to_string(), "python-install-default");
// Test multiple features
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
assert_eq!(features.to_string(), "python-upgrade,json-output");
}
#[test]
fn test_preview_display() {
// Test disabled
let preview = Preview::default();
assert_eq!(preview.to_string(), "disabled");
// Test enabled (all features)
let preview = Preview::all();
assert_eq!(preview.to_string(), "enabled");
// Test specific features
let preview = Preview::new(PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::PYLOCK);
assert_eq!(preview.to_string(), "python-upgrade,pylock");
}
#[test]
fn test_preview_from_args() {
// Test no_preview
let preview = Preview::from_args(true, true, &[]);
assert_eq!(preview.to_string(), "disabled");
// Test preview (all features)
let preview = Preview::from_args(true, false, &[]);
assert_eq!(preview.to_string(), "enabled");
// Test specific features
let features = vec![
PreviewFeatures::PYTHON_UPGRADE,
PreviewFeatures::JSON_OUTPUT,
];
let preview = Preview::from_args(false, false, &features);
assert!(preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE));
assert!(preview.is_enabled(PreviewFeatures::JSON_OUTPUT));
assert!(!preview.is_enabled(PreviewFeatures::PYLOCK));
}
#[test]
fn test_as_str_single_flags() {
assert_eq!(
PreviewFeatures::PYTHON_INSTALL_DEFAULT.flag_as_str(),
"python-install-default"
);
assert_eq!(
PreviewFeatures::PYTHON_UPGRADE.flag_as_str(),
"python-upgrade"
);
assert_eq!(PreviewFeatures::JSON_OUTPUT.flag_as_str(), "json-output");
assert_eq!(PreviewFeatures::PYLOCK.flag_as_str(), "pylock");
assert_eq!(PreviewFeatures::ADD_BOUNDS.flag_as_str(), "add-bounds");
assert_eq!(
PreviewFeatures::EXTRA_BUILD_DEPENDENCIES.flag_as_str(),
"extra-build-dependencies"
);
}
#[test]
#[should_panic(expected = "`flag_as_str` can only be used for exactly one feature flag")]
fn test_as_str_multiple_flags_panics() {
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
let _ = features.flag_as_str();
}
}

View file

@ -4,11 +4,7 @@
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum ProjectBuildBackend { pub enum ProjectBuildBackend {
#[cfg_attr( #[cfg_attr(feature = "clap", value(alias = "uv-build", alias = "uv_build"))]
feature = "clap",
value(alias = "uv-build", alias = "uv_build", hide = true)
)]
#[cfg_attr(feature = "schemars", schemars(skip))]
/// Use uv as the project build backend. /// Use uv as the project build backend.
Uv, Uv,
#[serde(alias = "hatchling")] #[serde(alias = "hatchling")]

View file

@ -1,5 +1,6 @@
use std::fmt::Formatter; #[cfg(feature = "schemars")]
use std::str::FromStr; use std::borrow::Cow;
use std::{fmt::Formatter, str::FromStr};
use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError}; use uv_pep440::{Version, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError};
@ -36,20 +37,15 @@ impl FromStr for RequiredVersion {
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
impl schemars::JsonSchema for RequiredVersion { impl schemars::JsonSchema for RequiredVersion {
fn schema_name() -> String { fn schema_name() -> Cow<'static, str> {
String::from("RequiredVersion") Cow::Borrowed("RequiredVersion")
} }
fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { fn json_schema(_generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
schemars::schema::SchemaObject { schemars::json_schema!({
instance_type: Some(schemars::schema::InstanceType::String.into()), "type": "string",
metadata: Some(Box::new(schemars::schema::Metadata { "description": "A version specifier, e.g. `>=0.5.0` or `==0.5.0`."
description: Some("A version specifier, e.g. `>=0.5.0` or `==0.5.0`.".to_string()), })
..schemars::schema::Metadata::default()
})),
..schemars::schema::SchemaObject::default()
}
.into()
} }
} }

View file

@ -1,4 +1,6 @@
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)] #[serde(rename_all = "kebab-case", deny_unknown_fields)]
pub enum SourceStrategy { pub enum SourceStrategy {
/// Use `tool.uv.sources` when resolving dependencies. /// Use `tool.uv.sources` when resolving dependencies.

View file

@ -33,7 +33,7 @@ pub enum TargetTriple {
#[serde(rename = "i686-pc-windows-msvc")] #[serde(rename = "i686-pc-windows-msvc")]
I686PcWindowsMsvc, I686PcWindowsMsvc,
/// An x86 Linux target. Equivalent to `x86_64-manylinux_2_17`. /// An x86 Linux target. Equivalent to `x86_64-manylinux_2_28`.
#[cfg_attr(feature = "clap", value(name = "x86_64-unknown-linux-gnu"))] #[cfg_attr(feature = "clap", value(name = "x86_64-unknown-linux-gnu"))]
#[serde(rename = "x86_64-unknown-linux-gnu")] #[serde(rename = "x86_64-unknown-linux-gnu")]
#[serde(alias = "x8664-unknown-linux-gnu")] #[serde(alias = "x8664-unknown-linux-gnu")]
@ -56,7 +56,7 @@ pub enum TargetTriple {
#[serde(alias = "x8664-apple-darwin")] #[serde(alias = "x8664-apple-darwin")]
X8664AppleDarwin, X8664AppleDarwin,
/// An ARM64 Linux target. Equivalent to `aarch64-manylinux_2_17`. /// An ARM64 Linux target. Equivalent to `aarch64-manylinux_2_28`.
#[cfg_attr(feature = "clap", value(name = "aarch64-unknown-linux-gnu"))] #[cfg_attr(feature = "clap", value(name = "aarch64-unknown-linux-gnu"))]
#[serde(rename = "aarch64-unknown-linux-gnu")] #[serde(rename = "aarch64-unknown-linux-gnu")]
Aarch64UnknownLinuxGnu, Aarch64UnknownLinuxGnu,
@ -226,6 +226,10 @@ pub enum TargetTriple {
#[serde(rename = "aarch64-manylinux_2_40")] #[serde(rename = "aarch64-manylinux_2_40")]
#[serde(alias = "aarch64-manylinux240")] #[serde(alias = "aarch64-manylinux240")]
Aarch64Manylinux240, Aarch64Manylinux240,
/// A wasm32 target using the Pyodide 2024 platform. Meant for use with Python 3.12.
#[cfg_attr(feature = "clap", value(name = "wasm32-pyodide2024"))]
Wasm32Pyodide2024,
} }
impl TargetTriple { impl TargetTriple {
@ -236,7 +240,7 @@ impl TargetTriple {
Self::Linux | Self::X8664UnknownLinuxGnu => Platform::new( Self::Linux | Self::X8664UnknownLinuxGnu => Platform::new(
Os::Manylinux { Os::Manylinux {
major: 2, major: 2,
minor: 17, minor: 28,
}, },
Arch::X86_64, Arch::X86_64,
), ),
@ -258,7 +262,7 @@ impl TargetTriple {
Self::Aarch64UnknownLinuxGnu => Platform::new( Self::Aarch64UnknownLinuxGnu => Platform::new(
Os::Manylinux { Os::Manylinux {
major: 2, major: 2,
minor: 17, minor: 28,
}, },
Arch::Aarch64, Arch::Aarch64,
), ),
@ -450,6 +454,13 @@ impl TargetTriple {
}, },
Arch::Aarch64, Arch::Aarch64,
), ),
Self::Wasm32Pyodide2024 => Platform::new(
Os::Pyodide {
major: 2024,
minor: 0,
},
Arch::Wasm32,
),
} }
} }
@ -490,6 +501,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "aarch64", Self::Aarch64Manylinux238 => "aarch64",
Self::Aarch64Manylinux239 => "aarch64", Self::Aarch64Manylinux239 => "aarch64",
Self::Aarch64Manylinux240 => "aarch64", Self::Aarch64Manylinux240 => "aarch64",
Self::Wasm32Pyodide2024 => "wasm32",
} }
} }
@ -530,6 +542,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "Linux", Self::Aarch64Manylinux238 => "Linux",
Self::Aarch64Manylinux239 => "Linux", Self::Aarch64Manylinux239 => "Linux",
Self::Aarch64Manylinux240 => "Linux", Self::Aarch64Manylinux240 => "Linux",
Self::Wasm32Pyodide2024 => "Emscripten",
} }
} }
@ -570,6 +583,10 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "", Self::Aarch64Manylinux238 => "",
Self::Aarch64Manylinux239 => "", Self::Aarch64Manylinux239 => "",
Self::Aarch64Manylinux240 => "", Self::Aarch64Manylinux240 => "",
// This is the value Emscripten gives for its version:
// https://github.com/emscripten-core/emscripten/blob/4.0.8/system/lib/libc/emscripten_syscall_stubs.c#L63
// It doesn't really seem to mean anything? But for completeness we include it here.
Self::Wasm32Pyodide2024 => "#1",
} }
} }
@ -610,6 +627,9 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "", Self::Aarch64Manylinux238 => "",
Self::Aarch64Manylinux239 => "", Self::Aarch64Manylinux239 => "",
Self::Aarch64Manylinux240 => "", Self::Aarch64Manylinux240 => "",
// This is the Emscripten compiler version for Pyodide 2024.
// See https://pyodide.org/en/stable/development/abi.html#pyodide-2024-0
Self::Wasm32Pyodide2024 => "3.1.58",
} }
} }
@ -650,6 +670,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "posix", Self::Aarch64Manylinux238 => "posix",
Self::Aarch64Manylinux239 => "posix", Self::Aarch64Manylinux239 => "posix",
Self::Aarch64Manylinux240 => "posix", Self::Aarch64Manylinux240 => "posix",
Self::Wasm32Pyodide2024 => "posix",
} }
} }
@ -690,6 +711,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "linux", Self::Aarch64Manylinux238 => "linux",
Self::Aarch64Manylinux239 => "linux", Self::Aarch64Manylinux239 => "linux",
Self::Aarch64Manylinux240 => "linux", Self::Aarch64Manylinux240 => "linux",
Self::Wasm32Pyodide2024 => "emscripten",
} }
} }
@ -730,6 +752,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => true, Self::Aarch64Manylinux238 => true,
Self::Aarch64Manylinux239 => true, Self::Aarch64Manylinux239 => true,
Self::Aarch64Manylinux240 => true, Self::Aarch64Manylinux240 => true,
Self::Wasm32Pyodide2024 => false,
} }
} }

View file

@ -62,7 +62,7 @@ pub static RAYON_PARALLELISM: AtomicUsize = AtomicUsize::new(0);
/// `LazyLock::force(&RAYON_INITIALIZE)`. /// `LazyLock::force(&RAYON_INITIALIZE)`.
pub static RAYON_INITIALIZE: LazyLock<()> = LazyLock::new(|| { pub static RAYON_INITIALIZE: LazyLock<()> = LazyLock::new(|| {
rayon::ThreadPoolBuilder::new() rayon::ThreadPoolBuilder::new()
.num_threads(RAYON_PARALLELISM.load(Ordering::SeqCst)) .num_threads(RAYON_PARALLELISM.load(Ordering::Relaxed))
.stack_size(min_stack_size()) .stack_size(min_stack_size())
.build_global() .build_global()
.expect("failed to initialize global rayon pool"); .expect("failed to initialize global rayon pool");

View file

@ -1,4 +1,6 @@
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
#[cfg(feature = "schemars")]
use std::borrow::Cow;
use std::str::FromStr; use std::str::FromStr;
use url::Url; use url::Url;
@ -143,20 +145,15 @@ impl std::fmt::Display for TrustedHost {
#[cfg(feature = "schemars")] #[cfg(feature = "schemars")]
impl schemars::JsonSchema for TrustedHost { impl schemars::JsonSchema for TrustedHost {
fn schema_name() -> String { fn schema_name() -> Cow<'static, str> {
"TrustedHost".to_string() Cow::Borrowed("TrustedHost")
} }
fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { fn json_schema(_generator: &mut schemars::generate::SchemaGenerator) -> schemars::Schema {
schemars::schema::SchemaObject { schemars::json_schema!({
instance_type: Some(schemars::schema::InstanceType::String.into()), "type": "string",
metadata: Some(Box::new(schemars::schema::Metadata { "description": "A host or host-port pair."
description: Some("A host or host-port pair.".to_string()), })
..schemars::schema::Metadata::default()
})),
..schemars::schema::SchemaObject::default()
}
.into()
} }
} }

View file

@ -1,8 +1,14 @@
[package] [package]
name = "uv-console" name = "uv-console"
version = "0.0.1" version = "0.0.1"
edition = { workspace = true }
description = "Utilities for interacting with the terminal" description = "Utilities for interacting with the terminal"
edition = { workspace = true }
rust-version = { workspace = true }
homepage = { workspace = true }
documentation = { workspace = true }
repository = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
[lib] [lib]
doctest = false doctest = false

View file

@ -6,6 +6,25 @@ use std::{cmp::Ordering, iter};
/// This is a slimmed-down version of `dialoguer::Confirm`, with the post-confirmation report /// This is a slimmed-down version of `dialoguer::Confirm`, with the post-confirmation report
/// enabled. /// enabled.
pub fn confirm(message: &str, term: &Term, default: bool) -> std::io::Result<bool> { pub fn confirm(message: &str, term: &Term, default: bool) -> std::io::Result<bool> {
confirm_inner(message, None, term, default)
}
/// Prompt the user for confirmation in the given [`Term`], with a hint.
pub fn confirm_with_hint(
message: &str,
hint: &str,
term: &Term,
default: bool,
) -> std::io::Result<bool> {
confirm_inner(message, Some(hint), term, default)
}
fn confirm_inner(
message: &str,
hint: Option<&str>,
term: &Term,
default: bool,
) -> std::io::Result<bool> {
let prompt = format!( let prompt = format!(
"{} {} {} {} {}", "{} {} {} {} {}",
style("?".to_string()).for_stderr().yellow(), style("?".to_string()).for_stderr().yellow(),
@ -18,6 +37,13 @@ pub fn confirm(message: &str, term: &Term, default: bool) -> std::io::Result<boo
); );
term.write_str(&prompt)?; term.write_str(&prompt)?;
if let Some(hint) = hint {
term.write_str(&format!(
"\n\n{}{} {hint}",
style("hint").for_stderr().bold().cyan(),
style(":").for_stderr().bold()
))?;
}
term.hide_cursor()?; term.hide_cursor()?;
term.flush()?; term.flush()?;
@ -56,7 +82,14 @@ pub fn confirm(message: &str, term: &Term, default: bool) -> std::io::Result<boo
.cyan(), .cyan(),
); );
if hint.is_some() {
term.clear_last_lines(2)?;
// It's not clear why we need to clear to the end of the screen here, but it fixes lingering
// display of the hint on `bash` (the issue did not reproduce on `zsh`).
term.clear_to_end_of_screen()?;
} else {
term.clear_line()?; term.clear_line()?;
}
term.write_line(&report)?; term.write_line(&report)?;
term.show_cursor()?; term.show_cursor()?;
term.flush()?; term.flush()?;

View file

@ -40,14 +40,16 @@ anyhow = { workspace = true }
clap = { workspace = true, features = ["derive", "wrap_help"] } clap = { workspace = true, features = ["derive", "wrap_help"] }
fs-err = { workspace = true, features = ["tokio"] } fs-err = { workspace = true, features = ["tokio"] }
itertools = { workspace = true } itertools = { workspace = true }
markdown = { version = "0.3.0" } markdown = { version = "1.0.0" }
owo-colors = { workspace = true } owo-colors = { workspace = true }
poloto = { version = "19.1.2", optional = true } poloto = { version = "19.1.2", optional = true }
pretty_assertions = { version = "1.4.1" } pretty_assertions = { version = "1.4.1" }
reqwest = { workspace = true }
resvg = { version = "0.29.0", optional = true } resvg = { version = "0.29.0", optional = true }
schemars = { workspace = true } schemars = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
serde_yaml = { version = "0.9.34" }
tagu = { version = "0.1.6", optional = true } tagu = { version = "0.1.6", optional = true }
textwrap = { workspace = true } textwrap = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }

View file

@ -4,7 +4,7 @@ use clap::Parser;
use tracing::info; use tracing::info;
use uv_cache::{Cache, CacheArgs}; use uv_cache::{Cache, CacheArgs};
use uv_configuration::Concurrency; use uv_configuration::{Concurrency, Preview};
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest}; use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
#[derive(Parser)] #[derive(Parser)]
@ -26,6 +26,7 @@ pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
&PythonRequest::default(), &PythonRequest::default(),
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
&cache, &cache,
Preview::default(),
)? )?
.into_interpreter(); .into_interpreter();
interpreter.sys_executable().to_path_buf() interpreter.sys_executable().to_path_buf()

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use crate::{ use crate::{
generate_cli_reference, generate_env_vars_reference, generate_json_schema, generate_cli_reference, generate_env_vars_reference, generate_json_schema,
generate_options_reference, generate_options_reference, generate_sysconfig_mappings,
}; };
#[derive(clap::Args)] #[derive(clap::Args)]
@ -26,10 +26,12 @@ pub(crate) enum Mode {
DryRun, DryRun,
} }
pub(crate) fn main(args: &Args) -> Result<()> { pub(crate) async fn main(args: &Args) -> Result<()> {
generate_json_schema::main(&generate_json_schema::Args { mode: args.mode })?; generate_json_schema::main(&generate_json_schema::Args { mode: args.mode })?;
generate_options_reference::main(&generate_options_reference::Args { mode: args.mode })?; generate_options_reference::main(&generate_options_reference::Args { mode: args.mode })?;
generate_cli_reference::main(&generate_cli_reference::Args { mode: args.mode })?; generate_cli_reference::main(&generate_cli_reference::Args { mode: args.mode })?;
generate_env_vars_reference::main(&generate_env_vars_reference::Args { mode: args.mode })?; generate_env_vars_reference::main(&generate_env_vars_reference::Args { mode: args.mode })?;
generate_sysconfig_mappings::main(&generate_sysconfig_mappings::Args { mode: args.mode })
.await?;
Ok(()) Ok(())
} }

View file

@ -24,7 +24,7 @@ const REPLACEMENTS: &[(&str, &str)] = &[
// TODO(zanieb): In general, we should show all of the environment variables in the reference // TODO(zanieb): In general, we should show all of the environment variables in the reference
// but this one is non-standard so it's the only one included right now. When we tackle the rest // but this one is non-standard so it's the only one included right now. When we tackle the rest
// we can fix the formatting. // we can fix the formatting.
(" [env: &quot;UV<em>PYTHON</em>DOWNLOADS=never&quot;]", ""), (" [env: &quot;UV_PYTHON_DOWNLOADS=never&quot;]", ""),
]; ];
const SHOW_HIDDEN_COMMANDS: &[&str] = &["generate-shell-completion"]; const SHOW_HIDDEN_COMMANDS: &[&str] = &["generate-shell-completion"];

View file

@ -21,7 +21,7 @@ pub(crate) fn main(args: &Args) -> anyhow::Result<()> {
let filename = "environment.md"; let filename = "environment.md";
let reference_path = PathBuf::from(ROOT_DIR) let reference_path = PathBuf::from(ROOT_DIR)
.join("docs") .join("docs")
.join("configuration") .join("reference")
.join(filename); .join(filename);
match args.mode { match args.mode {

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use anstream::println; use anstream::println;
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use pretty_assertions::StrComparison; use pretty_assertions::StrComparison;
use schemars::{JsonSchema, schema_for}; use schemars::JsonSchema;
use serde::Deserialize; use serde::Deserialize;
use uv_settings::Options as SettingsOptions; use uv_settings::Options as SettingsOptions;
@ -91,7 +91,10 @@ const REPLACEMENTS: &[(&str, &str)] = &[
/// Generate the JSON schema for the combined options as a string. /// Generate the JSON schema for the combined options as a string.
fn generate() -> String { fn generate() -> String {
let schema = schema_for!(CombinedOptions); let settings = schemars::generate::SchemaSettings::draft07();
let generator = schemars::SchemaGenerator::new(settings);
let schema = generator.into_root_schema_for::<CombinedOptions>();
let mut output = serde_json::to_string_pretty(&schema).unwrap(); let mut output = serde_json::to_string_pretty(&schema).unwrap();
for (value, replacement) in REPLACEMENTS { for (value, replacement) in REPLACEMENTS {

View file

@ -402,6 +402,11 @@ mod tests {
#[test] #[test]
fn test_generate_options_reference() -> Result<()> { fn test_generate_options_reference() -> Result<()> {
// Skip this test in CI to avoid redundancy with the dedicated CI job
if env::var_os(EnvVars::CI).is_some() {
return Ok(());
}
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") { let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
Mode::Write Mode::Write
} else { } else {

View file

@ -0,0 +1,198 @@
//! Generate sysconfig mappings for supported python-build-standalone *nix platforms.
use anstream::println;
use anyhow::{Result, bail};
use pretty_assertions::StrComparison;
use serde::Deserialize;
use std::collections::BTreeMap;
use std::fmt::Write;
use std::path::PathBuf;
use crate::ROOT_DIR;
use crate::generate_all::Mode;
/// Contains current supported targets
const TARGETS_YML_URL: &str = "https://raw.githubusercontent.com/astral-sh/python-build-standalone/refs/tags/20250723/cpython-unix/targets.yml";
#[derive(clap::Args)]
pub(crate) struct Args {
#[arg(long, default_value_t, value_enum)]
pub(crate) mode: Mode,
}
#[derive(Debug, Deserialize)]
struct TargetConfig {
host_cc: Option<String>,
host_cxx: Option<String>,
target_cc: Option<String>,
target_cxx: Option<String>,
}
pub(crate) async fn main(args: &Args) -> Result<()> {
let reference_string = generate().await?;
let filename = "generated_mappings.rs";
let reference_path = PathBuf::from(ROOT_DIR)
.join("crates")
.join("uv-python")
.join("src")
.join("sysconfig")
.join(filename);
match args.mode {
Mode::DryRun => {
println!("{reference_string}");
}
Mode::Check => match fs_err::read_to_string(reference_path) {
Ok(current) => {
if current == reference_string {
println!("Up-to-date: {filename}");
} else {
let comparison = StrComparison::new(&current, &reference_string);
bail!(
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{comparison}"
);
}
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
bail!("{filename} not found, please run `cargo dev generate-sysconfig-metadata`");
}
Err(err) => {
bail!(
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{err}"
);
}
},
Mode::Write => match fs_err::read_to_string(&reference_path) {
Ok(current) => {
if current == reference_string {
println!("Up-to-date: {filename}");
} else {
println!("Updating: {filename}");
fs_err::write(reference_path, reference_string.as_bytes())?;
}
}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
println!("Updating: {filename}");
fs_err::write(reference_path, reference_string.as_bytes())?;
}
Err(err) => {
bail!(
"{filename} changed, please run `cargo dev generate-sysconfig-metadata`:\n{err}"
);
}
},
}
Ok(())
}
async fn generate() -> Result<String> {
println!("Downloading python-build-standalone cpython-unix/targets.yml ...");
let body = reqwest::get(TARGETS_YML_URL).await?.text().await?;
let parsed: BTreeMap<String, TargetConfig> = serde_yaml::from_str(&body)?;
let mut replacements: BTreeMap<&str, BTreeMap<String, String>> = BTreeMap::new();
for targets_config in parsed.values() {
for sysconfig_cc_entry in ["CC", "LDSHARED", "BLDSHARED", "LINKCC"] {
if let Some(ref from_cc) = targets_config.host_cc {
replacements
.entry(sysconfig_cc_entry)
.or_default()
.insert(from_cc.to_string(), "cc".to_string());
}
if let Some(ref from_cc) = targets_config.target_cc {
replacements
.entry(sysconfig_cc_entry)
.or_default()
.insert(from_cc.to_string(), "cc".to_string());
}
}
for sysconfig_cxx_entry in ["CXX", "LDCXXSHARED"] {
if let Some(ref from_cxx) = targets_config.host_cxx {
replacements
.entry(sysconfig_cxx_entry)
.or_default()
.insert(from_cxx.to_string(), "c++".to_string());
}
if let Some(ref from_cxx) = targets_config.target_cxx {
replacements
.entry(sysconfig_cxx_entry)
.or_default()
.insert(from_cxx.to_string(), "c++".to_string());
}
}
}
let mut output = String::new();
// Opening statements
output.push_str("//! DO NOT EDIT\n");
output.push_str("//!\n");
output.push_str("//! Generated with `cargo run dev generate-sysconfig-metadata`\n");
output.push_str("//! Targets from <https://github.com/astral-sh/python-build-standalone/blob/20250723/cpython-unix/targets.yml>\n");
output.push_str("//!\n");
// Disable clippy/fmt
output.push_str("#![allow(clippy::all)]\n");
output.push_str("#![cfg_attr(any(), rustfmt::skip)]\n\n");
// Begin main code
output.push_str("use std::collections::BTreeMap;\n");
output.push_str("use std::sync::LazyLock;\n\n");
output.push_str("use crate::sysconfig::replacements::{ReplacementEntry, ReplacementMode};\n\n");
output.push_str(
"/// Mapping for sysconfig keys to lookup and replace with the appropriate entry.\n",
);
output.push_str("pub(crate) static DEFAULT_VARIABLE_UPDATES: LazyLock<BTreeMap<String, Vec<ReplacementEntry>>> = LazyLock::new(|| {\n");
output.push_str(" BTreeMap::from_iter([\n");
// Add Replacement Entries for CC, CXX, etc.
for (key, entries) in &replacements {
writeln!(output, " (\"{key}\".to_string(), vec![")?;
for (from, to) in entries {
writeln!(
output,
" ReplacementEntry {{ mode: ReplacementMode::Partial {{ from: \"{from}\".to_string() }}, to: \"{to}\".to_string() }},"
)?;
}
writeln!(output, " ]),")?;
}
// Add AR case last
output.push_str(" (\"AR\".to_string(), vec![\n");
output.push_str(" ReplacementEntry {\n");
output.push_str(" mode: ReplacementMode::Full,\n");
output.push_str(" to: \"ar\".to_string(),\n");
output.push_str(" },\n");
output.push_str(" ]),\n");
// Closing
output.push_str(" ])\n});\n");
Ok(output)
}
#[cfg(test)]
mod tests {
use std::env;
use anyhow::Result;
use uv_static::EnvVars;
use crate::generate_all::Mode;
use super::{Args, main};
#[tokio::test]
async fn test_generate_sysconfig_mappings() -> Result<()> {
let mode = if env::var(EnvVars::UV_UPDATE_SCHEMA).as_deref() == Ok("1") {
Mode::Write
} else {
Mode::Check
};
main(&Args { mode }).await
}
}

View file

@ -11,6 +11,7 @@ use crate::generate_cli_reference::Args as GenerateCliReferenceArgs;
use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs; use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs; use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs; use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
use crate::generate_sysconfig_mappings::Args as GenerateSysconfigMetadataArgs;
#[cfg(feature = "render")] #[cfg(feature = "render")]
use crate::render_benchmarks::RenderBenchmarksArgs; use crate::render_benchmarks::RenderBenchmarksArgs;
use crate::wheel_metadata::WheelMetadataArgs; use crate::wheel_metadata::WheelMetadataArgs;
@ -22,6 +23,7 @@ mod generate_cli_reference;
mod generate_env_vars_reference; mod generate_env_vars_reference;
mod generate_json_schema; mod generate_json_schema;
mod generate_options_reference; mod generate_options_reference;
mod generate_sysconfig_mappings;
mod render_benchmarks; mod render_benchmarks;
mod wheel_metadata; mod wheel_metadata;
@ -45,6 +47,8 @@ enum Cli {
GenerateCliReference(GenerateCliReferenceArgs), GenerateCliReference(GenerateCliReferenceArgs),
/// Generate the environment variables reference for the documentation. /// Generate the environment variables reference for the documentation.
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs), GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
/// Generate the sysconfig metadata from derived targets.
GenerateSysconfigMetadata(GenerateSysconfigMetadataArgs),
#[cfg(feature = "render")] #[cfg(feature = "render")]
/// Render the benchmarks. /// Render the benchmarks.
RenderBenchmarks(RenderBenchmarksArgs), RenderBenchmarks(RenderBenchmarksArgs),
@ -57,11 +61,12 @@ pub async fn run() -> Result<()> {
Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?, Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?,
Cli::Compile(args) => compile::compile(args).await?, Cli::Compile(args) => compile::compile(args).await?,
Cli::ClearCompile(args) => clear_compile::clear_compile(&args)?, Cli::ClearCompile(args) => clear_compile::clear_compile(&args)?,
Cli::GenerateAll(args) => generate_all::main(&args)?, Cli::GenerateAll(args) => generate_all::main(&args).await?,
Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?, Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?, Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?, Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?, Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
Cli::GenerateSysconfigMetadata(args) => generate_sysconfig_mappings::main(&args).await?,
#[cfg(feature = "render")] #[cfg(feature = "render")]
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?, Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
} }

View file

@ -6,7 +6,7 @@ use std::time::Instant;
use anstream::eprintln; use anstream::eprintln;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use tracing::debug; use tracing::{debug, trace};
use tracing_durations_export::DurationsLayerBuilder; use tracing_durations_export::DurationsLayerBuilder;
use tracing_durations_export::plot::PlotConfig; use tracing_durations_export::plot::PlotConfig;
use tracing_subscriber::filter::Directive; use tracing_subscriber::filter::Directive;
@ -68,6 +68,7 @@ async fn main() -> ExitCode {
let result = run().await; let result = run().await;
debug!("Took {}ms", start.elapsed().as_millis()); debug!("Took {}ms", start.elapsed().as_millis());
if let Err(err) = result { if let Err(err) = result {
trace!("Error trace: {err:?}");
eprintln!("{}", "uv-dev failed".red().bold()); eprintln!("{}", "uv-dev failed".red().bold());
for err in err.chain() { for err in err.chain() {
eprintln!(" {}: {}", "Caused by".red().bold(), err.to_string().trim()); eprintln!(" {}: {}", "Caused by".red().bold(), err.to_string().trim());

View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
# Fetch latest python-build-standalone tag
latest_tag=$(curl -fsSL -H "Accept: application/json" https://github.com/astral-sh/python-build-standalone/releases/latest | jq -r .tag_name)
# Validate we got a tag name back
if [[ -z "${latest_tag}" ]]; then
echo "Error: Failed to fetch the latest tag from astral-sh/python-build-standalone." >&2
exit 1
fi
# Edit the sysconfig mapping endpoints
sed -i.bak "s|refs/tags/[^/]\+/cpython-unix|refs/tags/${latest_tag}/cpython-unix|g" src/generate_sysconfig_mappings.rs && rm -f src/generate_sysconfig_mappings.rs.bak
sed -i.bak "s|blob/[^/]\+/cpython-unix|blob/${latest_tag}/cpython-unix|g" src/generate_sysconfig_mappings.rs && rm -f src/generate_sysconfig_mappings.rs.bak
# Regenerate mappings in case there's any changes
cargo dev generate-sysconfig-metadata

View file

@ -24,5 +24,5 @@ fs-err = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
[dev-dependencies] [dev-dependencies]
assert_fs = { version = "1.1.2" } assert_fs = { workspace = true }
indoc = { workspace = true } indoc = { workspace = true }

View file

@ -11,16 +11,18 @@ use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use thiserror::Error; use thiserror::Error;
use tracing::{debug, instrument, trace}; use tracing::{debug, instrument, trace};
use uv_build_backend::check_direct_build; use uv_build_backend::check_direct_build;
use uv_build_frontend::{SourceBuild, SourceBuildContext}; use uv_build_frontend::{SourceBuild, SourceBuildContext};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{ use uv_configuration::{
BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, PreviewMode, Reinstall, BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, PackageConfigSettings,
SourceStrategy, Preview, Reinstall, SourceStrategy,
}; };
use uv_configuration::{BuildOutput, Concurrency}; use uv_configuration::{BuildOutput, Concurrency};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
use uv_distribution::ExtraBuildRequires;
use uv_distribution_filename::DistFilename; use uv_distribution_filename::DistFilename;
use uv_distribution_types::{ use uv_distribution_types::{
CachedDist, DependencyMetadata, Identifier, IndexCapabilities, IndexLocations, CachedDist, DependencyMetadata, Identifier, IndexCapabilities, IndexLocations,
@ -35,8 +37,8 @@ use uv_resolver::{
PythonRequirement, Resolver, ResolverEnvironment, PythonRequirement, Resolver, ResolverEnvironment,
}; };
use uv_types::{ use uv_types::{
AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, EmptyInstalledPackages, HashStrategy, AnyErrorBuild, BuildArena, BuildContext, BuildIsolation, BuildStack, EmptyInstalledPackages,
InFlight, HashStrategy, InFlight,
}; };
use uv_workspace::WorkspaceCache; use uv_workspace::WorkspaceCache;
@ -87,17 +89,19 @@ pub struct BuildDispatch<'a> {
shared_state: SharedState, shared_state: SharedState,
dependency_metadata: &'a DependencyMetadata, dependency_metadata: &'a DependencyMetadata,
build_isolation: BuildIsolation<'a>, build_isolation: BuildIsolation<'a>,
extra_build_requires: &'a ExtraBuildRequires,
link_mode: uv_install_wheel::LinkMode, link_mode: uv_install_wheel::LinkMode,
build_options: &'a BuildOptions, build_options: &'a BuildOptions,
config_settings: &'a ConfigSettings, config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
hasher: &'a HashStrategy, hasher: &'a HashStrategy,
exclude_newer: Option<ExcludeNewer>, exclude_newer: ExcludeNewer,
source_build_context: SourceBuildContext, source_build_context: SourceBuildContext,
build_extra_env_vars: FxHashMap<OsString, OsString>, build_extra_env_vars: FxHashMap<OsString, OsString>,
sources: SourceStrategy, sources: SourceStrategy,
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
concurrency: Concurrency, concurrency: Concurrency,
preview: PreviewMode, preview: Preview,
} }
impl<'a> BuildDispatch<'a> { impl<'a> BuildDispatch<'a> {
@ -112,15 +116,17 @@ impl<'a> BuildDispatch<'a> {
shared_state: SharedState, shared_state: SharedState,
index_strategy: IndexStrategy, index_strategy: IndexStrategy,
config_settings: &'a ConfigSettings, config_settings: &'a ConfigSettings,
config_settings_package: &'a PackageConfigSettings,
build_isolation: BuildIsolation<'a>, build_isolation: BuildIsolation<'a>,
extra_build_requires: &'a ExtraBuildRequires,
link_mode: uv_install_wheel::LinkMode, link_mode: uv_install_wheel::LinkMode,
build_options: &'a BuildOptions, build_options: &'a BuildOptions,
hasher: &'a HashStrategy, hasher: &'a HashStrategy,
exclude_newer: Option<ExcludeNewer>, exclude_newer: ExcludeNewer,
sources: SourceStrategy, sources: SourceStrategy,
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
concurrency: Concurrency, concurrency: Concurrency,
preview: PreviewMode, preview: Preview,
) -> Self { ) -> Self {
Self { Self {
client, client,
@ -133,7 +139,9 @@ impl<'a> BuildDispatch<'a> {
dependency_metadata, dependency_metadata,
index_strategy, index_strategy,
config_settings, config_settings,
config_settings_package,
build_isolation, build_isolation,
extra_build_requires,
link_mode, link_mode,
build_options, build_options,
hasher, hasher,
@ -167,7 +175,7 @@ impl<'a> BuildDispatch<'a> {
impl BuildContext for BuildDispatch<'_> { impl BuildContext for BuildDispatch<'_> {
type SourceDistBuilder = SourceBuild; type SourceDistBuilder = SourceBuild;
fn interpreter(&self) -> &Interpreter { async fn interpreter(&self) -> &Interpreter {
self.interpreter self.interpreter
} }
@ -179,6 +187,10 @@ impl BuildContext for BuildDispatch<'_> {
&self.shared_state.git &self.shared_state.git
} }
fn build_arena(&self) -> &BuildArena<SourceBuild> {
&self.shared_state.build_arena
}
fn capabilities(&self) -> &IndexCapabilities { fn capabilities(&self) -> &IndexCapabilities {
&self.shared_state.capabilities &self.shared_state.capabilities
} }
@ -195,6 +207,10 @@ impl BuildContext for BuildDispatch<'_> {
self.config_settings self.config_settings
} }
fn config_settings_package(&self) -> &PackageConfigSettings {
self.config_settings_package
}
fn sources(&self) -> SourceStrategy { fn sources(&self) -> SourceStrategy {
self.sources self.sources
} }
@ -207,6 +223,10 @@ impl BuildContext for BuildDispatch<'_> {
&self.workspace_cache &self.workspace_cache
} }
fn extra_build_dependencies(&self) -> &uv_workspace::pyproject::ExtraBuildDependencies {
&self.extra_build_requires.extra_build_dependencies
}
async fn resolve<'data>( async fn resolve<'data>(
&'data self, &'data self,
requirements: &'data [Requirement], requirements: &'data [Requirement],
@ -219,13 +239,14 @@ impl BuildContext for BuildDispatch<'_> {
let resolver = Resolver::new( let resolver = Resolver::new(
Manifest::simple(requirements.to_vec()).with_constraints(self.constraints.clone()), Manifest::simple(requirements.to_vec()).with_constraints(self.constraints.clone()),
OptionsBuilder::new() OptionsBuilder::new()
.exclude_newer(self.exclude_newer) .exclude_newer(self.exclude_newer.clone())
.index_strategy(self.index_strategy) .index_strategy(self.index_strategy)
.build_options(self.build_options.clone()) .build_options(self.build_options.clone())
.flexibility(Flexibility::Fixed) .flexibility(Flexibility::Fixed)
.build(), .build(),
&python_requirement, &python_requirement,
ResolverEnvironment::specific(marker_env), ResolverEnvironment::specific(marker_env),
self.interpreter.markers(),
// Conflicting groups only make sense when doing universal resolution. // Conflicting groups only make sense when doing universal resolution.
Conflicts::empty(), Conflicts::empty(),
Some(tags), Some(tags),
@ -289,6 +310,8 @@ impl BuildContext for BuildDispatch<'_> {
self.hasher, self.hasher,
self.index_locations, self.index_locations,
self.config_settings, self.config_settings,
self.config_settings_package,
self.extra_build_dependencies(),
self.cache(), self.cache(),
venv, venv,
tags, tags,
@ -412,6 +435,17 @@ impl BuildContext for BuildDispatch<'_> {
build_stack.insert(dist.distribution_id()); build_stack.insert(dist.distribution_id());
} }
// Get package-specific config settings if available; otherwise, use global settings.
let config_settings = if let Some(name) = dist_name {
if let Some(package_settings) = self.config_settings_package.get(name) {
package_settings.clone().merge(self.config_settings.clone())
} else {
self.config_settings.clone()
}
} else {
self.config_settings.clone()
};
let builder = SourceBuild::setup( let builder = SourceBuild::setup(
source, source,
subdirectory, subdirectory,
@ -425,13 +459,15 @@ impl BuildContext for BuildDispatch<'_> {
self.index_locations, self.index_locations,
sources, sources,
self.workspace_cache(), self.workspace_cache(),
self.config_settings.clone(), config_settings,
self.build_isolation, self.build_isolation,
self.extra_build_dependencies(),
&build_stack, &build_stack,
build_kind, build_kind,
self.build_extra_env_vars.clone(), self.build_extra_env_vars.clone(),
build_output, build_output,
self.concurrency.builds, self.concurrency.builds,
self.preview,
) )
.boxed_local() .boxed_local()
.await?; .await?;
@ -446,12 +482,6 @@ impl BuildContext for BuildDispatch<'_> {
build_kind: BuildKind, build_kind: BuildKind,
version_id: Option<&'data str>, version_id: Option<&'data str>,
) -> Result<Option<DistFilename>, BuildDispatchError> { ) -> Result<Option<DistFilename>, BuildDispatchError> {
// Direct builds are a preview feature with the uv build backend.
if self.preview.is_disabled() {
trace!("Preview is disabled, not checking for direct build");
return Ok(None);
}
let source_tree = if let Some(subdir) = subdirectory { let source_tree = if let Some(subdir) = subdirectory {
source.join(subdir) source.join(subdir)
} else { } else {
@ -519,6 +549,8 @@ pub struct SharedState {
index: InMemoryIndex, index: InMemoryIndex,
/// The downloaded distributions. /// The downloaded distributions.
in_flight: InFlight, in_flight: InFlight,
/// Build directories for any PEP 517 builds executed during resolution or installation.
build_arena: BuildArena<SourceBuild>,
} }
impl SharedState { impl SharedState {
@ -531,6 +563,7 @@ impl SharedState {
Self { Self {
git: self.git.clone(), git: self.git.clone(),
capabilities: self.capabilities.clone(), capabilities: self.capabilities.clone(),
build_arena: self.build_arena.clone(),
..Default::default() ..Default::default()
} }
} }
@ -554,4 +587,9 @@ impl SharedState {
pub fn capabilities(&self) -> &IndexCapabilities { pub fn capabilities(&self) -> &IndexCapabilities {
&self.capabilities &self.capabilities
} }
/// Return the [`BuildArena`] used by the [`SharedState`].
pub fn build_arena(&self) -> &BuildArena<SourceBuild> {
&self.build_arena
}
} }

View file

@ -27,7 +27,6 @@ rkyv = { workspace = true, features = ["smallvec-1"] }
serde = { workspace = true } serde = { workspace = true }
smallvec = { workspace = true } smallvec = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
url = { workspace = true }
[dev-dependencies] [dev-dependencies]
insta = { version = "1.40.0" } insta = { workspace = true }

View file

@ -5,7 +5,6 @@ use std::str::FromStr;
use memchr::memchr; use memchr::memchr;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use thiserror::Error; use thiserror::Error;
use url::Url;
use uv_cache_key::cache_digest; use uv_cache_key::cache_digest;
use uv_normalize::{InvalidNameError, PackageName}; use uv_normalize::{InvalidNameError, PackageName};
@ -300,29 +299,6 @@ impl WheelFilename {
} }
} }
impl TryFrom<&Url> for WheelFilename {
type Error = WheelFilenameError;
fn try_from(url: &Url) -> Result<Self, Self::Error> {
let filename = url
.path_segments()
.ok_or_else(|| {
WheelFilenameError::InvalidWheelFileName(
url.to_string(),
"URL must have a path".to_string(),
)
})?
.next_back()
.ok_or_else(|| {
WheelFilenameError::InvalidWheelFileName(
url.to_string(),
"URL must contain a filename".to_string(),
)
})?;
Self::from_str(filename)
}
}
impl<'de> Deserialize<'de> for WheelFilename { impl<'de> Deserialize<'de> for WheelFilename {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where

Some files were not shown because too many files have changed in this diff Show more