## Summary
We can read from the slice directly. I don't think this will affect
performance today, because `from_str` will then allocate, but it
_should_ be a speedup once #10475 merges, since we can then avoid
allocating a `String` and go straight from `str` to `ArcStr`.
#8061 incorrectly claims to change the delimiter for `UV_FIND_LINKS`
from spaces to commas. In reality, it prevents `UV_FIND_LINKS` from
being split. This commit fixes that.
## Summary
This appears to be a consistent 1% performance improvement and should
also reduce memory quite a bit. We've also decided to use these for
markers, so it's nice to use the same optimization here.
```
❯ hyperfine "./uv pip compile --universal scripts/requirements/airflow.in" "./arcstr pip compile --universal scripts/requirements/airflow.in" --min-runs 50 --warmup 20
Benchmark 1: ./uv pip compile --universal scripts/requirements/airflow.in
Time (mean ± σ): 136.3 ms ± 4.0 ms [User: 139.1 ms, System: 241.9 ms]
Range (min … max): 131.5 ms … 149.5 ms 50 runs
Benchmark 2: ./arcstr pip compile --universal scripts/requirements/airflow.in
Time (mean ± σ): 134.9 ms ± 3.2 ms [User: 137.6 ms, System: 239.0 ms]
Range (min … max): 130.1 ms … 151.8 ms 50 runs
Summary
./arcstr pip compile --universal scripts/requirements/airflow.in ran
1.01 ± 0.04 times faster than ./uv pip compile --universal scripts/requirements/airflow.in
```
It turns out that we use `UniversalMarker::pep508` quite a bit. To the
point that it makes sense to pre-compute it when constructing a
`UniversalMarker`.
This still isn't necessarily the fastest thing we can do, but this
results in a major speed-up and `without_extras` no longer shows up for
me in a profile.
Motivating benchmarks. First, from #10430:
```
$ hyperfine 'rm -f uv.lock && uv lock' 'rm -f uv.lock && uv-ag-optimize-without-extras lock'
Benchmark 1: rm -f uv.lock && uv lock
Time (mean ± σ): 408.3 ms ± 276.6 ms [User: 333.6 ms, System: 111.1 ms]
Range (min … max): 316.9 ms … 1195.3 ms 10 runs
Warning: The first benchmarking run for this command was significantly slower than the rest (1.195 s). This could be caused by (filesystem) caches that were not filled until after the first run. You should consider using the '--warmup' option to fill those caches before the actual benchmark. Alternatively, use the '--prepare' option to clear the caches before each timing run.
Benchmark 2: rm -f uv.lock && uv-ag-optimize-without-extras lock
Time (mean ± σ): 209.4 ms ± 2.2 ms [User: 209.8 ms, System: 103.8 ms]
Range (min … max): 206.1 ms … 213.4 ms 14 runs
Summary
rm -f uv.lock && uv-ag-optimize-without-extras lock ran
1.95 ± 1.32 times faster than rm -f uv.lock && uv lock
```
And now from #10438:
```
$ hyperfine 'uv pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null' 'uv-ag-optimize-without-extras pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null'
Benchmark 1: uv pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null
Time (mean ± σ): 12.718 s ± 0.052 s [User: 12.818 s, System: 0.140 s]
Range (min … max): 12.650 s … 12.815 s 10 runs
Benchmark 2: uv-ag-optimize-without-extras pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null
Time (mean ± σ): 419.5 ms ± 6.7 ms [User: 434.7 ms, System: 100.6 ms]
Range (min … max): 412.7 ms … 434.3 ms 10 runs
Summary
uv-ag-optimize-without-extras pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null ran
30.32 ± 0.50 times faster than uv pip compile requirements.in -c constraints.txt --universal --no-progress --python-version 3.8 --offline > /dev/null
```
Fixes#10430, Fixes#10438
## Summary
We shouldn't consider incompatible distributions (e.g., those that don't
match the required Python version) when determining the implied markers.
For some reason this was banned when originally added (I did not see
discussion about it). I think it's fine to allow. With `uv run`, there's
a bit of nuance because we also allow the script to be read from stdin.
## Summary
If a user provides a constraint like `flask==3.0.0`, that gets expanded
to `[3.0.0, 3.0.0+[max])`. So it's not a _singleton_, but it should be
treated as such for the purposes of prioritization, since in practice it
will almost always map to a single version.
This should be essentially the exact same behaviour, but backon is a
total API redesign, so things had to be expressed slightly differently.
Overall I think the code is more readable, which is nice.
Fixes#10001
## Summary
The issue here is that we add `urllib3{python_full_version >= '3.8'}` as
a dependency, then `requests{python_full_version >= '3.8'}`, which adds
`urllib3`, but at that point, we haven't expanded
`urllib3{python_full_version >= '3.8'}`, so we "lose" the singleton
constraint. The solution is to ensure that we visit proxies eagerly, so
that we accumulate constraints as early as possible.
Closes
https://github.com/astral-sh/uv/issues/10425#issuecomment-2580324578.
## Summary
You can now run `uv tree --script main.py` to show the dependency tree
for a given script. If a lockfile doesn't exist, it will create one.
Closes https://github.com/astral-sh/uv/issues/7328.
## Summary
`uv add --script main.py anyio` will now update the lockfile, _if_ it
already exists. (If no such lockfile exists, the behavior is unchanged.)
## Summary
This PR adds `ls` alias to `uv {tool, python, pip} list` for
convenience.
Not sure if folks previously discussed this or have any opinion on
having aliases – but I have a muscle memory for `ls` for listing things
in commands I'm using (like `docker images ls`, `zellij ls`, `helm ls`
etc.) and thought having `ls` alias for `list` command would be useful.
## Test Plan
I simply compiled `uv` and manually checked `./target/release/uv {tool,
python, pip} ls`.
## Summary
You can now run `uv lock --script main.py` to lock a given script
(though as of this PR, the script itself isn't used anywhere).
Closes https://github.com/astral-sh/uv/issues/6318.
The shellcheck action we uses misses some files, so they fell out of
spec for what we support. This PR first and foremost adds them to the
scanning list, and then fixes the issues found.
Fixes#7480
## Summary
This PR revives https://github.com/astral-sh/uv/pull/7827 to improve
tool resolutions such that, if the resolution fails, and the selected
interpreter doesn't match the required Python version from the solve, we
attempt to re-solve with a newly-discovered interpreter that _does_
match the required Python version.
For now, we attempt to choose a Python interpreter that's greater than
the inferred `requires-python`, but compatible with the same Python
minor. This helps avoid successive failures for cases like Posting,
where choosing Python 3.13 fails because it has a dependency that lacks
source distributions and doesn't publish any Python 3.13 wheels. We
should further improve the strategy to solve _that_ case too, but this
is at least the more conservative option...
In short, if you do `uv tool instal posting`, and we find Python 3.8 on
your machine, we'll detect that `requires-python: >=3.11`, then search
for the latest Python 3.11 interpreter and re-resolve.
Closes https://github.com/astral-sh/uv/issues/6381.
Closes https://github.com/astral-sh/uv/issues/10282.
## Test Plan
The following should succeed:
```
cargo run python uninstall --all
cargo run python install 3.8
cargo run tool install posting
```
In the logs, we see:
```
...
DEBUG No compatible version found for: posting
DEBUG Refining interpreter with: Python >=3.11, <3.12
DEBUG Searching for Python >=3.11, <3.12 in managed installations or search path
DEBUG Searching for managed installations at `/Users/crmarsh/.local/share/uv/python`
DEBUG Skipping incompatible managed installation `cpython-3.8.20-macos-aarch64-none`
DEBUG Found `cpython-3.13.1-macos-aarch64-none` at `/opt/homebrew/bin/python3` (search path)
DEBUG Skipping interpreter at `/opt/homebrew/opt/python@3.13/bin/python3.13` from search path: does not satisfy request `>=3.11, <3.12`
DEBUG Found `cpython-3.11.7-macos-aarch64-none` at `/opt/homebrew/bin/python3.11` (search path)
DEBUG Re-resolving with Python 3.11.7
DEBUG Using request timeout of 30s
DEBUG Solving with installed Python version: 3.11.7
DEBUG Solving with target Python version: >=3.11.7
DEBUG Adding direct dependency: posting*
DEBUG Searching for a compatible version of posting (*)
...
```
This test started failing on main.
I don't understand why this changed (there was a new release but exclude-newer is supposed to exclude those), but the error message improved.
PowerPC seems to build without errors if we upgrade `zlib-ng`, but
upgrading `zlib-ng` causes Windows to break
(https://github.com/rust-lang/libz-sys/issues/225), and Cargo doesn't
let us include two different versions.
s390x fails because it can't find `stfle`. It's possible that we could
fix this by by upgrading our manylinux version and/or by upgrading GCC
(which may necessitate upgrading our manylinux version), but I don't
know if it's fixable without one of those things? And it's not worth
bumping compatibility for that reason. \cc @konstin
This happened as a result of #10345 and #10362 being merged
independently. The latter used the old `Version::release` API, but the
former changed the `Version::release` API. This PR tweaks the new test
to use the new API (i.e., force a deref on the proxy type).
Basically, this explicitly checks that parsing a `1.2.0` into a
`Version` will roundtrip back to a `1.2.0`, and that parsing a `1.2`
will roundtrip back to a `1.2`.
I think this case is included in the other tests in this module, but
this test makes the behavior more clearly intentional I think.
Ref #10345
Ref https://github.com/astral-sh/uv/issues/10344
Not a performance optimization, but the function had become too large.
No logic changes, just code moving around. Looks slightly better when
ignoring whitespace changes.
It's still too complex but i haven't found an apt simplification.
## Summary
This allows, e.g., `uv remove flask[dotenv]` to remove `flask`. Like
`pip install` and `uv pip install`, the content after the package name
has no effect.
Closes https://github.com/astral-sh/uv/issues/9764.
<!--
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
https://docs.rs/serde_json/latest/serde_json/fn.from_reader.html
suggests that
> When reading from a source against which short reads are not
efficient, such as a
[File](https://doc.rust-lang.org/std/fs/struct.File.html), you will want
to apply your own buffering because serde_json will not buffer the
input. See
[std::io::BufReader](https://doc.rust-lang.org/std/io/struct.BufReader.html).
Without this buffering, we observe a sequence of single byte reads which
can be quite inefficient depending on the underlying filesystem.
This adds buffering with `std::io::BufReader` to resolve this.
<!-- What's the purpose of the change? What does it do, and why? -->
## Test Plan
Unit tests cover this code.
<!-- How was it tested? -->