Now that uv’s MSRV is Rust 1.94, use Rust 2024 let chains where they
make nested guards clearer in the parser, configuration, and data-model
crates.
This flattens related pattern matches and predicates while preserving
evaluation order, short-circuiting, borrow scopes, and mutation
behavior. Guards involving effects, staged work, or non-obvious
lifetimes remain nested.
## Summary
This is a refactor of `uv_python::implementation::ImplementationName`.
It gets rid of the From impls in favour of just having functions which
returns the long and short names for an implementation. I think this is
just strictly cleaner at the call sites, and is less code. It gets rid
of the `long_names` and `short_names` functions in favour of using the
existing `iter_all`. It uses these changes to centralise a bunch of the
information so the short and long names aren't duplicated in various
locations anymore.
The PR becomes most useful for the centralised environments PR but the
refactor seemed helpful stand-alone and is completely isolated from that
PR.
## Test Plan
Relies on existing coverage.
Now that uv’s MSRV is Rust 1.94, use clearer `Option` and `Result`
predicate helpers where it makes sense.
This replaces `map(...).unwrap_or(...)` probes with APIs such as
`is_some_and`, `is_none_or`, and `is_ok_and`, preserving existing
ownership and `None`/`Err` behavior.
## Summary
While centralising the whole environment, I noticed that this code was
unnecessarily complicated so I deleted it.
Using `remove_dir` instead of `junction::delete` also fixes a bug of
sorts if we were to actually encounter a regular directory symlink on
windows.
`junction::get_target` has this weird quirk where it will produce
non-verbatim long paths. This means that prefix comparisons will work
assuming the prefix isn't a verbatim path (so actually this is a bug
disguised as a feature).
To avoid the opposite issue in this case, it's necessary to verbatim
both paths.
## Test Plan
Existing coverage, some augmentations, and a targeted test for a
verbatim_path idiom.
## Summary
Prior to this change, a Unicode numeric character in a Python version
request could cause variant parsing to panic. The parser treated the
character's byte offset as though the character were one byte long, then
sliced through the middle of it.
This PR restricts variant detection to ASCII digits, matching Python
version syntax. Malformed Unicode numeric requests now return the
existing invalid-version error.
## Test plan
- `cargo test -p uv-python version_request_from_str`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Pull in metadata from python-build-standalone 20260610 which includes
CPython 3.13.14 and 3.14.6
Note that this includes the change from #19786
---------
Co-authored-by: Tomasz (Tom) Kramkowski <tom@astral.sh>
## Summary
Fix `fetch-download-metadata.py` by having the GraalPy platform
information be processed before parsing the Python version information.
## Test Plan
* Ran script locally. Without this change it fails.
## Summary
Consolidate the sequential and parallel Python discovery paths
introduced in #18684.
Both modes now share a single `PythonRequest` dispatcher and
executable-to-installation pipeline. A private `QueryStrategy` selects
either lazy sequential querying or eager parallel querying while
preserving the existing filtering, ordering, and error-handling
behavior.
No prefetching is introduced here. Sequential discovery still defers
reading and traversing `PATH`, advances candidate executables one at a
time, and stops querying after finding an acceptable installation. The
pre-existing eager behavior for explicit file, directory, and
executable-name requests is unchanged.
## Test Plan
- Added parity coverage across every `PythonRequest` variant, using
independent caches and out-of-order query completion to verify ordered
results and non-critical error handling.
- Added regression coverage proving sequential strategy construction
pulls no candidates, one iteration pulls exactly one candidate, later
`PATH` directories are not inspected early, and later interpreters are
not queried after a match.
- Mutation-checked the laziness tests against candidate collection,
eager interpreter querying, and eager `PATH` directory filtering.
- `cargo test -p uv-python`
- `cargo test -p uv --test python python_list --no-fail-fast`
- `cargo test -p uv --test python python_find --no-fail-fast`
- `cargo +stable clippy -p uv-python --tests --no-deps --locked -- -D
warnings`
- `cargo +stable fmt --all -- --check`
#18684 accidentally regressed handling of non-critical errors when path
and directory Python requests are collected in parallel rather than
sequentially.
Currently, Python discovery happens sequentially — which is good most of
the time because uv will lazily exit once it finds a satisfactory
version. However, in `uv python list`, uv needs to query all
interpreters on the system which makes sequential discovery quite slow.
Here, we add parallelization to discovery. Annoyingly, it means a fair
amount of code repetition, but I've done my best to minimize that.
In the long-term, we may want to consolidate these code paths such that
uv can do prefetching during normal discovery, since technically if the
interpreter we want is far down the PATH then laziness does not save us
anything.
```
Benchmark 1: main
Time (mean ± σ): 3.108 s ± 0.026 s [User: 2.290 s, System: 0.386 s]
Range (min … max): 3.072 s … 3.157 s 8 runs
Benchmark 2: branch
Time (mean ± σ): 414.1 ms ± 11.1 ms [User: 2955.2 ms, System: 743.7 ms]
Range (min … max): 398.1 ms … 429.5 ms 8 runs
Summary
branch ran
7.51 ± 0.21 times faster than main
```
With https://github.com/oracle/graalpython/pull/810 we will slightly
alter upcoming GraalPy release artifact naming. The name will now
include the compatible CPython version name in the filename. This change
adapts the metadata script to support both the older and newer format.
We can drop the older one once support for GraalPy versions older than
25.1 is removed.
/cc @msimacek
Related: https://github.com/oracle/graalpython/issues/623
## Summary
This expands the usage of global preview in a key area which has
wide-ranging impact.
Key notes:
* uv-dev needs to set up default global preview because of this.
Although it seems like it should technically have been setting it up
earlier?
* A number of tests no longer pass `Preview::default()` but also don't
use the guard. This is because they only call into the preview stuff
when the relevant conda environment variables are present. Which we
assume they're not (otherwise the tests would be invalid for other
reasons). There's really a hermeticity issue here, but I've addressed it
in a separate PR.
## Test Plan
Tests have been modified, but existing coverage should be sufficient.
## Summary
This PR runs [hawk](https://github.com/astral-sh/hawk) over the uv
codebase to:
1. Remove dead code (i.e., code marked as `pub` that isn't called by any
other crates).
2. Reduce visibility of symbols (i.e., to make code non-`pub` if only
called internally, etc.).
I skimmed through the changes and added exceptions where they felt
warranted (to `hawk.toml`). I've included the `hawk.toml` file in the
prior commit, but am excluding it from being committed, since it's not
at a point that we have automated tooling.
## Summary
Keep the sysconfig generator aware of compiler paths that appeared in
older downloadable `python-build-standalone` releases, so regenerating
the mappings on current `main` does not drop support for previously
shipped aarch64 and riscv64 binaries.
## Context
uv patches compiler paths embedded in managed Python `sysconfig` data to
use portable `cc` and `c++` commands. These mappings are generated from
the current python-build-standalone targets.
Older python-build-standalone releases remain downloadable and retain
the compiler paths used when they were built. When a target changes
toolchains or is removed from the current targets, regenerating the
mappings silently drops support for those releases.
This previously removed the aarch64 GNU mappings. The upcoming
python-build-standalone sync in #19531 would similarly replace the
riscv64 GNU mappings with LLVM mappings.
## Test plan
I've manually verified, that before this patch, on an arm64 linux box:
```
% uvx python3.12.10 -c 'import sysconfig; print(sysconfig.get_config_var("CC"))'
/usr/bin/aarch64-linux-gnu-gcc -pthread
```
and after (after uninstalling the python version using `uv python
uninstall 3.12.10`):
```
% ./target/debug/uvx python3.12.10 -c 'import sysconfig; print(sysconfig.get_config_var("CC"))'
cc -pthread
```
## Summary
`uv-python` has some unit tests for python discovery. Python discovery
is sensitive to various environment variables. The code tries to be
"hermetic" by dropping some significant ones and setting others to fixed
values, but it misses some conda specific environment variables.
This PR fixes this gap by just using `EnvVars::all_names` to drop all
environment variables that uv cares about eagerly to avoid this and
similar future gaps.
## Test Plan
Existing coverage.
## Summary
Previously installing a windows python on linux failed, because the
windows python install does not have a `python` binary and it does not
use a `_sysconfigdata_*` file.
## Test Plan
Manually tested by running `uv python install
cpython-3.12.3-windows-x86_64-none`
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
<!--
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 adds PyEmscripten platform, which is standardized in [PEP
783](https://peps.python.org/pep-0783/). This basically replaces the
Pyodide platform. I kept the Pyodide platform for backward
compatibility.
## Test Plan
`cargo test`
## Why
Dependency linting needs to connect imported Python modules back to the
packages in a workspace resolution so it can identify unused
dependencies and imports that are undeclared or only indirect. `uv
workspace metadata` already exposes the resolution graph; this adds the
module ownership data needed to use that graph for linting.
## What changed
- Adds `--sync` to `uv workspace metadata`. When requested, uv syncs the
environment in inexact mode with all extras and dependency groups, then
adds a `module_owners` mapping from importable module names to
resolution package node IDs when mapped modules are present.
- Makes `--sync` conflict with `--dry-run`, since module ownership is
determined from installed distributions after syncing.
- Adds a validated `ModuleName` type and `InstalledDist::read_modules`,
which derives module names from distribution `RECORD` entries.
- Detects Python modules from packages, `.py` files, legacy sourceless
`.pyc` files, and supported extension-module filenames; parent packages
are recorded as owners as well.
- Filters owners through the selected installed resolution, so
distributions outside that resolution and virtual workspace packages do
not produce metadata entries.
A module may be owned by more than one package, for example when two
distributions provide entries under the same namespace package.
## Limitations
Editable installs that only record a `.pth` file do not currently
provide module ownership entries and will require separate handling.
This adds abstractions for handing hints, pulling them out of ad-hoc
addendums to error messages and treating them as a first-class concept
so we can render them more consistently.
The key concepts are:
- `Hints`: a wrapper struct for `Vec<Cow<'a, str>>`
- `Hint`: a trait with `hints(&self) -> Hints<'_>`
Error types now `impl Hint` to provide hints. This means errors need to
carry more information to construct the `Hint` lazily instead of ahead
of time. The majority of refactoring around error types is to support
that change.
When displaying errors, we
[downcast](https://github.com/astral-sh/uv/pull/18090/changes#r2935662966)
to each type known to implement the trait and extract hints. We then
display all the hints after the error chain is complete.
The user-facing affect of this is that hints are now always rendered
outside the error chain.
This is a blocker to #17110 and is pulled out of that project. There is
still some weirdness with miette's `help:` prompts that will be removed
entirely in a following change.
---------
Co-authored-by: Codex <noreply@openai.com>
## Summary
This is a Codex-driven PR to remove as many `pub` interfaces as we can,
and then fixing the resulting Clippy violations. (I then read the diff
and reverted some changes.)
We use `pub` to expose members across crates within our workspace, even
though we don't intend each of those `pub` members to be usable API --
we are largely our only caller. (I've explicitly retained pieces that we
added to our API based on prior requests from other users.) As a result,
we can remove >1,000 unused LOC.
## Summary
Right now, it appears that we parse the JSON manifest for ~every lock
and sync (I _think_ this regressed in b9826778b). By avoiding that work,
this PR improves (warm) `uv lock` from 38.94ms to 24.06ms (38.2%
faster!), and (warm) `uv sync` from 146.96ms to 129.80ms.
Note that we _do_ need to read it if you're using a pre-release, since
we have this dedicated pre-release warning.
Closes https://github.com/astral-sh/uv/issues/19397.