## Summary
Adds hidden `uv check --show-version` support, matching the existing `uv
format --show-version` convention. The flag now reports `Using ty
<version>` for both `TY` executable overrides and resolved/downloaded ty
binaries, without relying on debug logging or the separate lock-pinning
work.
This threads the hidden flag through CLI/settings/check execution and
updates focused integration coverage for both version-selection paths.
## Summary
We added a global workspace lock for project-oriented uv commands
creating/re-creating venvs but the same was not done for `uv venv` when
it operates on a project environment.
This PR remedies this.
## Test Plan
There's a new test, not sure how good of an idea it is to set RUST_LOG
there....
## Summary
Prior to this change, PEP 517 build hooks that invoked uv failed while
building a wheel from a source distribution. `uv build` extracts the
generated source distribution into uv's cache, so the nested uv
invocation treated the extracted project as an unsupported project
inside the configured cache and exited before the hook could complete.
This records the exact PEP 517 source tree in a hidden internal
environment variable and exempts nested uv invocations only when their
project directory is within that uv-managed tree. Other projects inside
the cache remain rejected, including paths that require canonicalization
to detect.
The regression coverage uses a Hatchling custom build hook that invokes
`uv export`, matching the reported failure while building both the
source distribution and wheel.
Closes https://github.com/astral-sh/uv/issues/19878.
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, uv parsed the `lock-version` field in
`pylock.toml` files but never checked whether that version was
supported. As a result, a lock file declaring an incompatible major
version such as `2.0` was installed normally.
This validates the lock version immediately after deserialization, both
when installing from a lock file and when reusing an existing output
file during an upgrade. Major version 1 remains forward-compatible with
later minor versions, while unsupported major versions now produce a
direct error as required by PEP 751.
The regression coverage verifies that version 2.0 is rejected and that a
future version 1.1 remains accepted.
## Summary
PEP 685 requires tools to reject extra names that collide after
normalization. Both the workspace parser and uv-build previously parsed
`project.optional-dependencies` directly into maps keyed by `ExtraName`,
so entries such as `foo-bar` and `foo_bar` silently overwrote one
another.
Detect duplicate normalized extra names during deserialization in both
paths and report a TOML parse error instead. The regression coverage
exercises both workspace and build-backend parsing.
## Summary
Prior to this change, a dependency-group object containing
`include-group` alongside additional keys was accepted as a group
include. We silently discarded the additional fields even though the
current specification defines an include object as containing exactly
one key.
This recognizes `include-group` only when it is the object's sole key.
Mixed tables are preserved as dependency object specifiers, allowing
future syntax to deserialize without being misinterpreted, while the
existing semantic validation rejects them when their group is processed.
The focused coverage verifies both that mixed tables retain all of their
fields during deserialization and that `uv lock` rejects the currently
unsupported object when resolving its group.
## Summary
Prior to this change, uv parsed `packages.requires-python` from
`pylock.toml` files but did not enforce it. A package selected for
installation could therefore require a different Python version than the
target environment.
This checks each selected package's Python requirement immediately after
evaluating its marker. Packages excluded by their marker remain skipped,
while a selected package with an incompatible requirement now produces a
direct error before its source is processed.
The regression coverage verifies both the skipped-marker case and the
incompatible selected-package case.
## Summary
Prior to this change, `uv pip list` assumed that every installed
editable direct URL could be converted to a local file path. An editable
`direct_url.json` containing a non-file URL caused both the columns and
JSON output formats to panic.
This handles the URL-to-path conversion fallibly and omits the editable
project location when the URL does not identify a local path, matching
`uv pip show`.
The regression test constructs the installed metadata directly and
verifies both output formats.
This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
| [criterion](https://codspeed.io)
([source](https://redirect.github.com/CodSpeedHQ/codspeed-rust)) |
dev-dependencies | minor | `4.6.0` → `4.7.0` |
---
### Release Notes
<details>
<summary>CodSpeedHQ/codspeed-rust (criterion)</summary>
###
[`v4.7.0`](https://redirect.github.com/CodSpeedHQ/codspeed-rust/releases/tag/v4.7.0)
[Compare
Source](https://redirect.github.com/CodSpeedHQ/codspeed-rust/compare/v4.6.0...v4.7.0)
#### What's Changed
##### Manual sampling for criterion
> **Note:** ignored under CodSpeed simulation mode (single measured
iteration). Only takes effect in walltime mode.
We introduced a new finer control way of defining a criterion benchmark
to have full control over how many times your code is ran.\
This bypasses criterion's original sampler, which we still recommend
using if you do not have specific control needs.
```rust
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion, IterManualOptions};
fn bench_my_function(c: &mut Criterion) {
c.bench_function("my_function", |b| {
b.iter_manual_unstable(
IterManualOptions::new()
.rounds(5) // 5 measurement samples, can be lower than criterion's imposed 10
.iters(1000) // 1000 calls per sample
.warmup(5), // 5 unmeasured warmup iterations
|| my_function(),
);
});
}
criterion_group!(benches, bench_my_function);
criterion_main!(benches);
```
Please note that this API is still under development and may change with
future releases.
- fix(cargo-codspeed): forward args after `--` to bench binaries by
[@​not-matthias](https://redirect.github.com/not-matthias) in
[#​179](https://redirect.github.com/CodSpeedHQ/codspeed-rust/pull/179)
- chore: bump instrument-hooks by
[@​not-matthias](https://redirect.github.com/not-matthias) in
[#​178](https://redirect.github.com/CodSpeedHQ/codspeed-rust/pull/178)
- feat(criterion-compat): add `iter_manual` to have finer control over
the iteration loop by
[@​GuillaumeLagrange](https://redirect.github.com/GuillaumeLagrange)
in
[#​180](https://redirect.github.com/CodSpeedHQ/codspeed-rust/pull/180)
**Full Changelog**:
<https://github.com/CodSpeedHQ/codspeed-rust/compare/v4.6.0...v4.7.0>
</details>
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`)
- 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:eyJjcmVhdGVkSW5WZXIiOiI0My4yMDkuNCIsInVwZGF0ZWRJblZlciI6IjQzLjIwOS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJidWlsZDpza2lwLWRvY2tlciIsImJ1aWxkOnNraXAtcmVsZWFzZSIsImludGVybmFsIl19-->
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## 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
This is a continuation of the excellent work by @j-helland in #16452 and
#17202 and closes#15767.
This PR adds `preview-features` to `uv.toml` and `pyproject.toml`.
This field can be set to a boolean or to a list of features.
It is intended to supersede the `preview` setting itself, and conflicts
with it.
There's a little bit of complexity required to ensure that setting
either `preview` or `preview-features` is combined at the right point,
but it's also necessary to leave them split to accurately warn when a
`uv.toml` masks a `pyproject.toml` in the same directory.
Additionally there's complexity involved in making things work with
`deny_unknown_fields` and `flatten` (they're incompatible so require
manual flattening) and also this improves error messages somewhat.
Also (supersedes) closes#16452 and (supersedes) closes#17202.
## Test Plan
Tests taken from the original PR with some alterations and a bunch of
additional tests.
---------
Co-authored-by: j-helland <jonathan.w.helland@gmail.com>
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
This addresses a small papercut: high-activity projects that publish to
PyPI generally prefer to have their wheels published first, so that
installations degrade gracefully (falling back to an older release)
rather than failing because the sdist fails to build.
This matches twine's behavior.
## Test Plan
One line change, added a test demonstrating upload order.
---------
Signed-off-by: William Woodruff <william@yossarian.net>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
## Summary
Prior to this change, we added `backend-path` entries to `sys.path`
without checking that they existed in the current source tree. When an
in-tree backend was omitted from an sdist, the subsequent wheel build
failed with `ModuleNotFoundError` and suggested that the backend was an
undeclared build dependency.
This validates each `backend-path` entry before resolving or invoking
the backend. Missing directories now produce a direct error explaining
that the configured path does not exist, matching the behavior of PyPA's
`build` frontend.
The regression test builds an sdist with a Flit wrapper in
`backend_dir`, intentionally omits that directory from the sdist, and
verifies the diagnostic during the wheel-from-sdist build.
Closes https://github.com/astral-sh/uv/issues/19771.
## Summary
Prior to this change, we used lexicographic ordering for pure
string-valued environment markers. For example, with `os_name =
"posix"`, both `os_name > "nt"` and `os_name >= "nt"` evaluated to true.
The [current dependency
specification](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#marker-comparisons),
updated by
[pypa/packaging.python.org#1988](https://github.com/pypa/packaging.python.org/pull/1988),
defines strict string comparisons (`>` and `<`) as always false, while
inclusive comparisons (`>=` and `<=`) are equivalent to equality. This
applies those rules to every pure String marker field, including
reversed operand forms.
`platform_release` and `platform_version` remain on their existing
comparison path because the specification types them as `Version |
String` rather than pure strings.
## Summary
Removes a few more template injections, drops a blanket permission.
Previously we couldn't address these because they're part of the
generated dist workflow, but now that we're committed to it being dirty
this is fine.
## Test Plan
See what happens in CI.
---------
Signed-off-by: William Woodruff <william@yossarian.net>
<!--
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
Each of these tests needs to connect to PyPI over the network.
Conditionalize them all on `test-pypi` to support offline testing.
## Test Plan
Applied as a downstream patch to the `uv` package in Fedora.
<!-- How was it tested? -->
## Summary
This is a one-line fix, the rest of the change is tests.
TL;DR is we have `Default` on this type, but we also need a serde
default marker to ensure that an empty or comment-only input
deserializes as expected.
Fixes#19811.
## Test Plan
Two new tests.
Signed-off-by: William Woodruff <william@yossarian.net>
## Summary
- make URL credential extraction fallible
- reject percent-decoded usernames and passwords that are not valid
UTF-8
- propagate credential decoding errors through index, Git, project,
publish, and HTTP client paths
- identify failing indexes with their display-safe URL
- add unit and end-to-end regression coverage
## Why
Lossy decoding replaced malformed bytes with U+FFFD, silently changing
the credential sent on the wire and collapsing distinct inputs. URL
parsing remains permissive; the error is raised only when converting URL
userinfo into uv's string credential model.
Follow-up to
https://github.com/astral-sh/uv/pull/19800#discussion_r3398777727.
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
- move the uv 0.10 release notes into `changelogs/0.10.x.md`
- order the archived releases from oldest to newest, matching the
existing archives
- replace the 0.10 entries in `CHANGELOG.md` with a link to the archive
## Test plan
- `npx prettier --check CHANGELOG.md changelogs/0.10.x.md`
- `git diff --check`
- verified all 13 releases from 0.10.0 through 0.10.12 were moved
without content loss
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, uv generated compatible musllinux platform tags in
ascending version order and put the generic `linux` tag first. Since
wheel tags are ordered from most to least preferred, this made older
musllinux wheels and the generic Linux fallback outrank the current
musllinux version.
This generates musllinux tags from the detected version down to 1.0,
then appends the generic Linux fallback last. It adds snapshot coverage
for musllinux 1.2 on x86-64.
## Summary
Prior to this change, the GraalPy ABI parser discarded the final tag
segment, so an invalid tag like `graalpy240_310_wrong` was accepted and
normalized to `graalpy240_310_native`.
This requires GraalPy ABI tags to end in exactly `_native` and rejects
unexpected or additional suffixes. It adds regression coverage for both
forms.
This is my proposed solution to the `uv -> ty -> uv` gordian know that
`uv check` uniquely presents. By doing this we get properly handling of
`--isolated`, `--index`, and so on "for free" by virtue of ty not
needing to call back into us. Also it's just more efficient than ty
doing a callback.
This *does not* preclude ty knowing how to call into uv when it's
invoked standalone, but in that case ty can be fully in charge of the
config/interface so we don't need to worry about preserving it (i.e. we
can just tell users to use persistent config or env-vars and they don't
have a reason to complain about consistency).
## Summary
Prior to this change, the Python download cache was omitted from the
list of current cache buckets. As a result, `uv cache prune` treated
`python-v0` as obsolete and removed it.
This PR includes the Python bucket in pruning's allowlist and adds
regression coverage that confirms cached downloads remain in place.
## Test plan
- `cargo test -p uv --test build cache_prune::prune_python_downloads --
--exact`
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, reading `entry_points.txt` treated every failure
as a missing file. Malformed metadata such as invalid UTF-8 therefore
caused declared entry points to be silently omitted.
This PR continues to allow missing entry-point metadata while
propagating other read errors.
## Test plan
- `cargo test -p uv-install-wheel invalid_utf8_entry_points`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, the PEP 508 parser rejected the optional trailing
comma in version specifier lists:
```text
foo>=1,<2,
foo(>=1,<2,)
```
This accepts one trailing comma in bare and parenthesized specifier
lists, including before an environment marker. Empty specifiers and
repeated commas remain invalid.
## Summary
Prior to this change, activation commands were only quoted when their
paths contained spaces. Apostrophes and other shell metacharacters could
therefore produce invalid or unsafe shell commands.
This PR matches Python's `shlex.quote` safe-character behavior so every
unsafe path is single-quoted.
## Test plan
- `cargo test -p uv-shell`
- `cargo clippy -p uv-shell --all-targets -- -D warnings`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, a malformed HTTP cache entry whose trailing
cache-policy length encoded `usize::MAX` could overflow when accounting
for the length marker. The cache reader panicked instead of treating the
entry as invalid.
This PR compares the declared policy length against the available bytes
before performing any arithmetic. Malformed entries now return the
existing archive-read error.
## Test plan
- `cargo test -p uv-client --test it
cached_client::reject_overflowing_cache_policy_length -- --exact`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, `uv cache prune --ci` failed when the cache root
existed without an `sdists-v9` bucket. CI pruning unconditionally walked
the source-distribution bucket, and `WalkDir` returned a not-found error
for the missing root.
This PR skips the source-distribution walk when the bucket does not
exist while preserving other filesystem errors. CI pruning now succeeds
as a no-op for an otherwise empty cache.
## Test plan
- `cargo test -p uv --test build cache_prune::prune_ci_empty_cache --
--exact`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Prior to this change, formatting an error for a trailing marker
expression used the number of remaining characters as a byte length. A
multibyte character followed by more input could therefore produce a
span ending inside a UTF-8 code point and panic while rendering the
diagnostic.
This PR derives the trailing span from byte offsets in the original
input. Malformed markers now render the full invalid suffix instead of
panicking.
## Test plan
- `cargo test -p uv-pep508 --lib`
Co-authored-by: Zanie Blue <contact@zanie.dev>
## 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
Prior to this change, `SourceDistFilename::parse` skipped the byte after
the expected package name without validating that it was a hyphen. A
malformed filename like `aX1.2.3.zip` was therefore accepted as version
`1.2.3` for package `a`.
This PR requires the version suffix to start with the expected
separator, so malformed filenames return the existing filename error.
## Test plan
- `cargo test -p uv-distribution-filename`
Co-authored-by: Zanie Blue <contact@zanie.dev>