4529 Commits

Author SHA1 Message Date
Zanie Blue
e38ac4900d Bump version to 0.5.31 (#11459) 2025-02-12 14:45:22 -06:00
Zanie Blue
de67d5453d Check for executable permissions in is_executable (#11430)
e.g., as in
https://docs.rs/is_executable/latest/src/is_executable/lib.rs.html#44
2025-02-12 13:50:29 -06:00
Scott Sanderson
7154800e0c Detect infinite recursion in uv run. (#11386)
<!--
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

Handle potential infinite recursion if `uv run` recursively invokes `uv
run`. This can happen if the shebang line of a script includes `uv run`,
but does not pass `--script`.

Handled by adding a new environment variable `UV_RUN_RECURSION_DEPTH`,
which contains a counter of the number of times that uv run has been
recursively invoked. If unset, it defaults to zero, and each time uv run
starts a subprocess we increment the counter, erroring if the value is
greater than a configurable (but not currently exposed or documented)
threshold.

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

## Test Plan

I've added a snapshot test to `uv/crates/uv/tests/it/run` that tests the
end-to-end recursion detection flow. I've currently made it a unix-only
test because I'm not sure offhand how uv run will interact with shebang
lines on windows.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-02-12 18:58:43 +00:00
Zanie Blue
81966c43dc Allow --python <dir> requests to match existing environments if sys.executable is the same file (#11290)
Closes https://github.com/astral-sh/uv/issues/11288

I tested the reproduction there manually.

I'm a little uncertain about this behavior, it's not true to the spirit
of `--python <dir>` selecting a target environment but this method is
only used to see if an existing environment matches for the purpose of
invalidation in projects and tools where I think we always force a
separate environment anyway?
2025-02-12 12:45:59 -06:00
Zanie Blue
3f6a7f9879 Prefer running executables in the environment with <name> over <name>/__main__.py (#11431)
Closes https://github.com/astral-sh/uv/issues/11423
Closes https://github.com/astral-sh/uv/issues/9167
Closes https://github.com/astral-sh/uv/pull/9722


c23fc4024e
demonstrates the behavior.
2025-02-12 12:08:55 -06:00
konsti
070120e1c2 Fix cross-drive script installation (#11167)
Fallback to copy if renaming a script doesn't work, similar to the site
packages installation.

Fixes #11163

**Test Plan**

Failing:
```
docker volume rm -f gh11163_usr_local_bin
docker run -v gh11163_usr_local_bin:/usr/local/bin -e UV_LINK_MODE=copy -v $(pwd):/io -it --rm ghcr.io/astral-sh/uv:0.5-python3.11-bookworm-slim uv pip install --system ruff
```

Passing:
```
cargo build --target x86_64-unknown-linux-musl
docker volume rm -f gh11163_usr_local_bin
docker run -v gh11163_usr_local_bin:/usr/local/bin -e UV_LINK_MODE=copy -v $(pwd):/io -it --rm ghcr.io/astral-sh/uv:0.5-python3.11-bookworm-slim /io/target/x86_64-unknown-linux-musl/debug/uv pip install --system ruff
```
2025-02-12 19:00:41 +01:00
konsti
62b7e16f3c Optional schemars dependency (#11449)
In preparation for `uv-build`, make schemars an optional dependency
consistently, so it will not be part of the `uv-build` dependency tree.
2025-02-12 18:20:19 +01:00
Charlie Marsh
7823147895 Add indexes in reverse-priority order (#11451)
## Summary

We need to add indexes in the order in which they're respected by the
resolver. Otherwise, we risk writing an index to the `pyproject.toml`
that is canonically equal (but not verbatim equivalent) to the index we
use during resolutin.

Closes https://github.com/astral-sh/uv/issues/11312.
2025-02-12 12:14:05 -05:00
github-actions[bot]
066fbb74b1 Sync latest Python releases (#11450)
See
https://github.com/astral-sh/python-build-standalone/releases/tag/20250212

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-02-12 10:25:20 -06:00
Charlie Marsh
792dc9d1c5 Add uv sync --script (#11361)
## Summary

The environment is located at a stable path within the cache, based on
the script's absolute path.

If a lockfile exists for the script, then we use our standard lockfile
semantics (i.e., update the lockfile if necessary, etc.); if not, we
just do a `uv pip sync` (roughly).

Example usage:

```
❯ uv init --script hello.py
Initialized script at `hello.py`

❯ uv add --script hello.py requests
Updated `hello.py`

❯ cargo run sync --script hello.py
Using script environment at: /Users/crmarsh/.cache/uv/environments-v1/hello-84e289fe3f6241a0
Resolved 5 packages in 3ms
Installed 5 packages in 12ms
 + certifi==2025.1.31
 + charset-normalizer==3.4.1
 + idna==3.10
 + requests==2.32.3
 + urllib3==2.3.0
```

Closes https://github.com/astral-sh/uv/issues/6637.
2025-02-12 16:02:16 +00:00
Charlie Marsh
1cd9c37151 Use stable environments for remote and stdin scripts (#11364)
## Summary

This is a follow-on to #11347 to use a stable directory for remote and
stdin scripts. The annoying piece here was figuring out what to use as
the cache key. For remote scripts, I'm using the URL; for stdin scripts,
there isn't any identifying information, so I'm just using a hash of the
metadata.
2025-02-12 00:54:46 +00:00
Charlie Marsh
79ad7a1ab9 Use a stable directory for (local) script virtual environments (#11347)
## Summary

Today, scripts use `CachedEnvironment`, which results in a different
virtual environment path every time the interpreter changes _or_ the
project requirements change. This makes it impossible to provide users
with a stable path to the script that they can use for (e.g.) directing
their editor.

This PR modifies `uv run` to use a stable path for local scripts (we
continue to use `CachedEnvironment` for remote scripts and scripts from
`stdin`). The logic now looks a lot more like it does for projects: we
`get_or_init` an environment, etc.

For now, the path to the script is like:
`environments-v1/4485801245a4732f`, where `4485801245a4732f` is a SHA of
the absolute path to the script. But I'm not picky on that :)
2025-02-12 00:45:26 +00:00
Aria Desires
ba5efa8aa4 retry local clones without hardlinks if they fail (#11421)
Fixes #11420

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Co-authored-by: Filippo Vicentini <filippovicentini@gmail.com>
2025-02-11 19:42:13 -05:00
Charlie Marsh
12d34e680e Bring parity to uvx and uv tool install requests (#11345)
## Summary

This PR refactors the whole `Target` abstraction, mostly to remove all
the repeated `From*` variants and logic in favor of a higher-level
struct that captures those details separately.

In doing so, it also adds support to `uvx` for unnamed requirements, for
parity with `uv tool install`. So, e.g., the following will show the
`flask` version:

```
uvx git+https://github.com/pallets/flask --version
```

I think this makes sense conceptually since we already support arbitrary
named requirements there.
2025-02-12 00:16:34 +00:00
Charlie Marsh
136593a1bb Allow PEP 508 requirements in tool requests (#11337)
## Summary

This allows previously-unsupported patterns like:

- `uvx ruff>=0.5.0`
- `uvx flask[dotenv]`

Closes https://github.com/astral-sh/uv/issues/6296.
2025-02-11 19:06:40 -05:00
Charlie Marsh
ecf40b993f Avoid comparing to system site packages in --dry-run mode (#11427)
## Summary

Right now, `uv sync --dry-run` returns the interpreter that _would've_
been used to create the environment; so we end up using _that_
interpreter's `site-packages`, and return changes relative to that
interpreter. Instead, we now create a temporary virtual environment and
compare against that.

Closes https://github.com/astral-sh/uv/issues/11422.
2025-02-11 17:51:18 -05:00
Charlie Marsh
2aaabb544d Allow source distributions to produce wheels with +local suffixes (#11429)
## Summary

We currently enforce that if you do `uv pip install
./dist/iniconfig-1.0.0.tar.gz`, the build _must_ produce a wheel like
`iniconfig-1.0.0-py3-none-any.whl` (i.e., the name and version must
match). It turns out some packages produce a wheel that has a local
suffix on it, like `vllm`. This PR makes the check a little more
permissive in that we now accept `1.0.0` or that version with a local
suffix (e.g., `1.0.0+cpu`). I don't love this practice, but we already
relaxed this check when _installing_ a wheel, so this seems reasonable:


5e15881dcc/crates/uv-install-wheel/src/install.rs (L50-L52)

Note that this is _still_ stricter than pip. pip seems to only require
that the package name is the same (i.e., `iniconfig` matches
`iniconfig`; but they'll happily install a wheel like
`iniconfig-2.0.0-py3-none-any.whl` given
`./dist/iniconfig-1.0.0.tar.gz`).

Closes https://github.com/astral-sh/uv/issues/11038.
2025-02-11 17:26:40 -05:00
Michał Górny
0735be21b9 Mark sync::sync_dry_run test as requiring python-managed (#11415)
## Summary

Mark `sync::sync_dry_run` as requiring `python-managed`, as it fails
with system Python executables due to extraneous Python packages being
installed:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Snapshot Summary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Snapshot: sync_dry_run
Source: crates/uv/tests/it/sync.rs:6574
────────────────────────────────────────────────────────────────────────────────
Expression: snapshot
────────────────────────────────────────────────────────────────────────────────
-old snapshot
+new results
────────────┬───────────────────────────────────────────────────────────────────
    5     5 │ Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
    6     6 │ Would create virtual environment at: .venv
    7     7 │ Resolved 2 packages in [TIME]
    8     8 │ Would create lockfile at: uv.lock
    9       │-Would download 1 package
   10       │-Would install 1 package
   11       │- + iniconfig==2.0.0
          9 │+Would uninstall 1310 packages
         10 │+ - a2wsgi==1.10.8
[…]
```

## Test Plan

```
cargo test --no-default-features --features=python,pypi,git
```
2025-02-11 09:55:46 +01:00
Charlie Marsh
86062f952e Capture intermediary snapshots in sync_dry_run (#11410)
## Summary

Get some more information to help debug #11376.
2025-02-10 22:12:05 +00:00
konsti
ddbc6e3150 Catch broken mac_ver() (#11396)
A user reported a homebrew Python that would raise an exception in the
interpreter probing script because `platform.mac_ver()` returned `('',
('', '', ''), '')` on his installation due to
https://github.com/Homebrew/homebrew-core/issues/206778

This is easy enough to catch and show a proper error message instead of
the Python backtrace.
2025-02-10 22:49:16 +01:00
Charlie Marsh
ca49495e4b Bump version to v0.5.30 (#11405) 2025-02-10 21:42:31 +00:00
Alex Lowe
ac06e1318a Add NO_BINARY and NO_BINARY_PACKAGE environment variables (#11399)
<!--
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 `NO_BINARY` and `NO_BINARY_PACKAGE` environment variables to
the uv CLI, allowing the user to specify packages to build from source
using environment variables. Its not a complete fix for #4291 as it does
not handle the `pip` subcommand.

## Test Plan

This was tested by running `uv sync` with various `UV_NO_BINARY` and
`UV_NO_BINARY_PACKAGE` environment variables set and checking that the
correct set of packages were compiled rather than taken from pre-built
wheels.

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-02-10 21:11:46 +00:00
Charlie Marsh
8c8bed9454 Avoid re-cloning name when populating ambiguous set (#11401) 2025-02-10 20:26:57 +00:00
Charlie Marsh
f1221a6676 Allow dynamic packages to be overloaded (#11400)
## Summary

Now that `version` is an optional field, we shouldn't error if an
unambiguous package is lacking a version. We can still enforce the same
guarantees via `source`, since we always set version and source
together, if the package is unambiguous. I also retained the same error
for non-local packages that lack a version like this.

Closes https://github.com/astral-sh/uv/issues/11384.
2025-02-10 20:21:02 +00:00
Andrew Gallant
2352e745a6 uv-resolver: fix conflict marker simplification bug
The underlying cause here, I believe, was that we weren't accounting
for the case where an edge could be visited *without* any extras
enabled. Because of that, we got into situations where we thought
there was only one path to an edge when there were actually more
paths. This in turn lead to us erroneously doing simplification where
it actually isn't justified. And in turn lead to duplicate versions
of the same package being installed in the same environment.

The fix for this ends up being really simple: in the case where we
don't add any conflict items for a package during graph traversal,
we materialize an empty set of conflicts to mark the case of no
extras being enabled when visiting the child edges. This is enough
to propagate the knowledge of multiple paths to the same edge and
causes us to avoid doing improper simplifications.

This does fix the problem in the snapshot, but it does also I think
lead to other cases where simplifications are no longer possible
(hence the changes to the airflow snapshot). But this seems
expected, since we are doing strictly less simplification than we
were before. It's unclear if all of those cases were actual bugs
or not though.
2025-02-10 09:17:31 -05:00
Andrew Gallant
a65f2df393 uv/tests: add regression test for multiple torch packages
The snapshot is too big to meaningfully read, but the problem is
in the dependencies of `torchmetrics`:

[[package]]
name = "torchmetrics"
version = "1.6.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "lightning-utilities" },
    { name = "numpy" },
    { name = "packaging" },
    { name = "torch", version = "2.2.1", source = { registry = "https://pypi.org/simple" } },
    { name = "torch", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "extra == 'extra-4-test-chgnet' or extra != 'extra-4-test-m3gnet'" },
]

The conflict markers here are overlapping, which means
both can be included in the same environment.
2025-02-10 09:17:31 -05:00
renovate[bot]
9f7b344b88 Update Rust crate rustc-hash to v2.1.1 (#11369) 2025-02-10 02:21:03 +00:00
Charlie Marsh
df7b7081fd Avoid empty trailing colon for empty requirements (#11362) 2025-02-09 14:32:14 -05:00
Charlie Marsh
d22a2dfd12 Allow sync and update environment methods to take modifications (#11346)
## Summary

I have a use-case for an inexact sync here, so putting this up
separately.
2025-02-09 02:30:50 +00:00
Zanie Blue
6dfac4559b Fix credential caching for index roots when URL ends in simple/ (#11336)
Closes https://github.com/astral-sh/uv/issues/11244

See test failure at
e12f98a3e4
2025-02-08 09:23:31 -06:00
Charlie Marsh
5d8168875a Ignore 'egg' fragment in HTML Simple API response (#11340)
## Summary

Closes https://github.com/astral-sh/uv/issues/11339.
2025-02-08 09:00:51 -05:00
Charlie Marsh
12e7abe093 Support extras in @ requests for tools (#11335)
## Summary

Closes https://github.com/astral-sh/uv/issues/11321.
2025-02-08 02:07:15 +00:00
Geoffrey Thomas
25e7209a33 Patch pkg-config files to be relocatable (#11291)
Previously, we patched pkg-config .pc files to have the absolute path to
the directory where we unpack a python-build-standalone release. As
discussed in #11028, we can use ${pcfiledir} in a .pc file to indicate
paths relative to the location of the file itself.

This change was implemented in astral-sh/python-build-standalone#507, so
for newer python-build-standalone releases, we don't need to do any
patching. Optimize this case by only modifying the .pc file if an actual
change is needed (which might be helpful down the line with hard links
or something). For older releases, change uv's patch to match what
python-build-standalone now does.
2025-02-07 17:03:55 -06:00
konsti
96ac4b72b1 Add docs for uv tool install --editable (#11280)
I also moved it down a bit below the more important options

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2025-02-07 22:56:54 +00:00
Charlie Marsh
9e98b0e0f7 Use refined specifiers when logging narrowed Python range (#11334)
## Summary

The narrowed ranges are now logged correctly:

```
DEBUG Narrowed `requires-python` bound to: >=3.10.0, <3.12
DEBUG Narrowed `requires-python` bound to: >=3.12
```

Closes https://github.com/astral-sh/uv/issues/11322.
2025-02-07 17:43:32 -05:00
Zanie Blue
03616ebb68 Add note about available versions (#11331)
ref https://github.com/astral-sh/uv/issues/11243#issuecomment-2644104492
2025-02-07 16:10:05 -06:00
konsti
6e5479f5db Optimize flattening in apache airflow workspace (#11313)
## Motivation

No-op `uv lock` in apache airflow
(891c67f210ab7c877d1f00ea6ea3d3cdbb0e96ef) is slow, which makes `uv run`
slow, too.

Reference project:

```
$ hyperfine "uv run python -c \"print('hi')\""
Benchmark 1: uv run python -c "print('hi')"
Time (mean ± σ):      16.3 ms ±   1.5 ms    [User: 9.8 ms, System: 6.4 ms]
Range (min … max):    13.0 ms …  20.0 ms    186 runs
```

Apache airflow before:

```
$ hyperfine "uv run python -c \"print('hi')\""
Benchmark 1: uv run python -c "print('hi')"
Time (mean ± σ):     161.0 ms ±   5.2 ms    [User: 135.3 ms, System: 24.1 ms]
Range (min … max):   155.0 ms … 176.3 ms    18 runs
```

## Optimization

`FlatRequiresDist::from_requirements` is taking 50% of main thread
runtime.

Before:


![image](https://github.com/user-attachments/assets/10ea76eb-d1e9-477c-b400-39e653eb8f3a)

After both commits:


![image](https://github.com/user-attachments/assets/5c578ff6-f80b-46bb-9b5f-8be8435c3d85)

Apache airflow after the first commit:

```
$ hyperfine "uv-profiling run python -c \"print('hi')\""
Benchmark 1: uv-profiling run python -c "print('hi')"
  Time (mean ± σ):     122.3 ms ±   5.4 ms    [User: 96.1 ms, System: 24.7 ms]
  Range (min … max):   114.0 ms … 133.2 ms    23 runs
```

Apache airflow after the second commit:

```
$ hyperfine "uv-profiling run python -c \"print('hi')\""
Benchmark 1: uv-profiling run python -c "print('hi')"
  Time (mean ± σ):     108.5 ms ±   3.4 ms    [User: 83.2 ms, System: 24.2 ms]
  Range (min … max):   103.6 ms … 119.9 ms    28 runs
```
2025-02-07 17:08:40 -05:00
Charlie Marsh
711766e79c Set 777 permissions on locked files (#11328)
## Summary

These are used for coordination across processes. If you run uv under,
e.g., the root user, then under a different user, I don't think we
should prevent you from acquiring the lock.

Closes https://github.com/astral-sh/uv/issues/11324.
2025-02-07 21:36:09 +00:00
Charlie Marsh
f0d9ed8e09 Add tests for uv add with and without trailing slash (#11332) 2025-02-07 16:33:05 -05:00
Charlie Marsh
cf366a557b Correct environment variable expansion in rustdoc (#11327)
## Summary

These comments are incorrect.
2025-02-07 19:51:40 +00:00
Aria Desires
161eb42cb9 don't use the Cool popup-generating eprintln in trampoline for warnings (#11295)
Also I refactored the code a bit to centralize all the calls of
eprintln.

Fixes #10706

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2025-02-07 13:33:12 -05:00
konsti
84b9ae2b92 Typo in release_specifiers_to_ranges docs (#11320) 2025-02-07 16:49:56 +00:00
Geoffrey Thomas
21369326ca uv-python tests: Use #!/bin/sh instead of #!/bin/bash (#11292)
NixOS has (and POSIX mandates) a /bin/sh but not a /bin/bash, so this
fixes tests on NixOS.
2025-02-07 09:42:33 -06:00
github-actions[bot]
69f1904aeb Sync latest Python releases (#11318)
Includes https://pypy.org/posts/2025/02/pypy-v7318-release.html

These are labeled as betas in the post but not anywhere obvious to me?
I'm not sure we need to portray this to users.

Co-authored-by: zanieb <2586601+zanieb@users.noreply.github.com>
2025-02-07 09:42:20 -06:00
Aria Desires
5c4b6d436c cleanup some dependency-group docs (#11284)
Some additional details, more mentioning of related flags, and some
minor rewordings to avoid misconceptions I had from the current docs.

Closes #11205
2025-02-07 15:40:59 +00:00
konsti
092e78d9d2 Un-nest satisfies_requires_dist (#11311)
Move the function to the top level, it doesn't need to be nested.
2025-02-07 10:54:40 +00:00
konsti
3e7ec1df05 Fix walkdir error message (#11310)
Fixes #11309
2025-02-07 10:24:05 +00:00
Charlie Marsh
46a03b5518 Use a DryRun enum everywhere (#11303)
## Summary

Rather than Yet Another Bool.
2025-02-07 00:42:49 +00:00
Charlie Marsh
51c05df9c9 Use an iterator for logging upgrade events (#11301)
## Summary

No behavior changes... This just separates the formatting from the
collection of the results, and also fixes a bug whereby we didn't say
"No changes detected" in some cases.
2025-02-07 00:13:58 +00:00
Charlie Marsh
8335a6d816 Add uv sync --dry-run (#11299)
## Summary

Allows users to understand how the environment will change prior to
committing.

Closes https://github.com/astral-sh/uv/issues/11282.
2025-02-06 23:52:49 +00:00