Commit graph

89 commits

Author SHA1 Message Date
konsti
316f683071
Update packse (#7002)
Add additional tests for https://github.com/astral-sh/uv/pull/6959 and
https://github.com/astral-sh/uv/pull/6961
2024-09-05 08:14:34 +00:00
Zanie Blue
1e89d3e44f
Remove VIRTUAL_ENV from project commmands by default (#6976)
And use test context helpers for commands consistently.

Needed for https://github.com/astral-sh/uv/pull/6864
2024-09-03 14:11:23 -05:00
Charlie Marsh
6333823236
Change the definition of --locked to require satisfaction check (#6102)
## Summary

This PR changes the definition of `--locked` from:

> Produces the same `Lock`

To:

> Passes `Lock::satisfies`

This is a subtle but important difference. Previous, if
`Lock::satisfies` failed, we would run a resolution, then do
`existing_lock == lock`. If the two weren't equal, and `--locked` was
specified, we'd throw an error.

The equality check is hard to get right. For example, it means that we
can't ship #6076 without changing our marker representation, since the
deserialized lockfile "loses" some of the internal marker state that
gets accumulated during resolution.

The downside of this change is that there could be scenarios in which
`uv lock --locked` fails even though the lockfile would actually work
and the exact TOML would be unchanged. But... I think it's ok if
`--locked` fails after the user modifies something?
2024-08-15 08:17:28 -04:00
Charlie Marsh
7b67b5a328
Strip SHA when constructing package source (#6097)
## Summary

Similar to #5805, but applies the normalization earlier so that
`--locked` passes for URLs that contain fragments.
2024-08-14 20:12:32 -04:00
Charlie Marsh
e3f345ce09
Validate lockfile (rather than re-resolve) in uv lock (#6091)
## Summary

Historically, in order to "resolve from a lockfile", we've taken the
lockfile, used it to pre-populate the in-memory metadata index, then run
a resolution. If the resolution didn't match our existing resolution, we
re-resolved from scratch.

This was an appealing approach because (in theory) it didn't require any
dedicated logic beyond pre-populating the index. However, it's proven to
be _really_ hard to get right, because it's a stricter requirement than
we need. We just need the current lockfile to _satisfy_ the requirements
provided by the user. We don't actually need a second resolution to
produce the exact same result. And it's not uncommon that this second
resolution differs, because we seed it with preferences, which
fundamentally changes its course. We've worked hard to minimize those
"instabilities", but they're still present.

The approach here is intended to be much simpler. Instead of resolving
from the lockfile, we just check if the current resolution satisfies the
state of the workspace. Specifically, we check if the lockfile (1)
contains all the relevant members, and (2) matches the metadata for all
dependencies, recursively. (We skip registry dependencies, assuming that
they're immutable.)

This may actually be too conservative, since we can have resolutions
that satisfy the requirements, even if the requirements have changed
slightly. But we want to bias towards correctness for now.

My hope is that this scheme will be more performant, simpler, and more
robust.

Closes https://github.com/astral-sh/uv/issues/6063.
2024-08-14 20:00:15 -04:00
Charlie Marsh
1bbb05dca7
Invalidate uv.lock if registry sources are removed (#6026)
## Summary

Now, if you resolve against a registry, then swap it out for another, we
won't reuse the lockfile. (If you don't provide any registry
configuration, then we won't enforce this, so that `uv lock --index-url
foo` and `uv lock` is stable.)

Closes https://github.com/astral-sh/uv/issues/5920.
2024-08-13 23:42:04 +00:00
konsti
1e6b021506
Update packse to 0.3.34 (#5954)
Preparation for #5905
2024-08-09 09:04:17 +00:00
konsti
ae6b59365f
Only textwrap json packse scenarios with packse 0.3.32 (#5810)
Companion change to https://github.com/astral-sh/packse/pull/205 to
correctly format lock scenario doc comments.

Updates packse to 0.3.32.
2024-08-08 15:49:50 +02:00
konsti
2247b0f540
Check idempotence in packse lock scenarios (#5485)
Add tests for the instabilities fix.

Part of
https://github.com/astral-sh/uv/issues/5180#issuecomment-2247696198

Closes #5180
2024-07-31 15:39:16 +00:00
konsti
194904b340
Redact packse version in snapshots follow-up (#5563)
I thought i had this included in #5483 but i had it on the wrong branch.
2024-07-29 15:22:20 +00:00
konsti
0f87d174b9
Redact packse version in snapshots (#5483)
Every packse version update is currently causing a huge diff (the size
of the `lock_scenarios.rs` diff in this PR). By redacting the version
from the snapshots, we will only have the actual change in the diff and
not the redundant version change noise.

The second commit moves all remaining packse url arg values to
`common/mod.rs`, which acts as a single source of truth for the packse
version.
2024-07-29 17:04:46 +02:00
konsti
f1eda3590b
Update to packse 0.3.31 (#5441)
Update packse to 0.3.31, adding the instability scenarios.
2024-07-26 15:39:29 +00:00
Andrew Gallant
b6ad41fd8e scenarios: bump to packse 0.3.30 2024-07-15 10:09:01 -07:00
Charlie Marsh
b629ab89c5
Set absolute URLs prior to uploading to PyPI (#5038)
## Summary

Closes https://github.com/astral-sh/uv/issues/5030.
2024-07-13 17:29:21 +00:00
Charlie Marsh
41f051db3b
Remove exclude newer methods on test context (#4535)
## Summary

Closes https://github.com/astral-sh/uv/issues/4531.
2024-06-25 23:45:35 +00:00
konsti
e6103dcab1
Deduplicate test command creation (#4512)
This PR refactors the command creation in the test suite to remove the
duplication.

**1)** We add the same set of test stubbing args to almost any uv
invocation in the tests:

```rust
command
    .arg("--cache-dir")
    .arg(self.cache_dir.path())
    .env("VIRTUAL_ENV", self.venv.as_os_str())
    .env("UV_NO_WRAP", "1")
    .env("HOME", self.home_dir.as_os_str())
    .env("UV_TOOLCHAIN_DIR", "")
    .env("UV_TEST_PYTHON_PATH", &self.python_path())
    .current_dir(self.temp_dir.path());

if cfg!(all(windows, debug_assertions)) {
    // TODO(konstin): Reduce stack usage in debug mode enough that the tests pass with the
    // default windows stack of 1MB
    command.env("UV_STACK_SIZE", (8 * 1024 * 1024).to_string());
}
```

Centralizing these into a `TestContext::add_shared_args` method removes
them from everywhere.

**2)** Prefix all `TextContext` methods of the pip interface with
`pip_`. This is now necessary due to `uv sync` vs. `uv pip sync`.

**3)** Move command creation in the various test files into dedicated
functions or methods to avoid repeating the arguments. Except for error
message tests, there should be at most one `Command::new(get_bin())`
call per test file. `EXCLUDE_NEWER` is exclusively used in
`TestContext`.

---

I'm considering adding a `TestCommand` on top of these changes (in
another PR) that holds a reference to the `TextContext`, has
`add_shared_args` as a method and uses `Fn(Self) -> Self` instead of
`Fn(&mut Self) -> Self` for methods to improved chaining.
2024-06-25 22:06:54 +00:00
Andrew Gallant
10c950a551 scenarios: bump to packse 0.3.29 2024-06-20 07:21:45 -04:00
Andrew Gallant
bb40d13603 scenarios: bump to packse 0.3.27 2024-06-17 09:30:37 -04:00
Andrew Gallant
eea1bf9bf2 scenarios: bump to packse 0.3.26 2024-06-17 09:30:37 -04:00
Zanie Blue
d963a0f085
Improve local testing docs for packse (#4279) 2024-06-12 13:19:10 -05:00
Andrew Gallant
910168a219 scenarios: bump packse to 0.3.24 2024-06-12 13:30:47 -04:00
Andrew Gallant
1e282da04a scripts/scenarios: add requires-python to packse lock test template
packse has the ability to specify a project wide Requires-Python
constraint, but our lock template wasn't forwarding this to the
corresponding pyproject.toml. This update makes that happen.
2024-06-12 13:30:47 -04:00
Andrew Gallant
c46fa74e65
make universal resolver fork only when markers are disjoint (#4135)
The basic idea here is to make it so forking can only ever result in a
resolution that, for a particular marker environment, will only install
at most one version of a package. We can guarantee this by ensuring we
only fork on conflicting dependency specifications only when their
corresponding markers are completely disjoint. If they aren't, then
resolution _must_ find a single version of the package in the
intersection of the two dependency specifications.

A test for this case has been added to packse here:
https://github.com/astral-sh/packse/pull/182. Previously, that test
would result in a resolution with two different unconditional versions
of the same package. With this change, resolution fails (as it should).

A commit-by-commit review should be helpful here, since the first commit
is a refactor to make the second commit a bit more digestible.
2024-06-07 23:40:55 +00:00
Andrew Gallant
42b584c668 scripts/scenarios: update packse to 0.3.17 2024-06-04 14:24:59 -04:00
Andrew Gallant
7b736fc238 scripts/scenarios: update 'generate.py' to handle universal tests
This commit adds a template and does some light surgery on `generate.py`
to make use of that template. In particular, the universal tests require
using the "workspace"-aware version of `uv`, so we can't use the
existing `uv pip {compile,install}` tests.
2024-06-04 14:24:59 -04:00
Andrew Gallant
459966a132
uv/tests: update packse tests (#4015)
This is just the result of running

    ./scripts/sync_scenarios.sh

From the root of the `uv` repository.

When I initially ran this, it produced some tests with snapshots that
weren't being updated. It turned out this was because the tests weren't
running, as they were gated behind the `python-patch` feature. In this
commit, we add `python-patch` to our `cargo insta` command, which should
update all relevant snapshots.

There are still some superfluous updates as a result of a spell checker
being run on generated files, but
2024-06-04 13:56:20 -04:00
konsti
005b76770e
Update BUILD_VENDOR_LINKS_URL from packse version (#3246)
Make `generate.py` update the packse version used in
`BUILD_VENDOR_LINKS_URL`.

Closes #3245
2024-04-24 17:54:38 +02:00
Zanie Blue
691b7d26a0
Upgrade packse to 0.3.15 (#3244)
Includes https://github.com/astral-sh/packse/pull/179 for #3225

```
uv pip compile scripts/scenarios/requirements.in -o scripts/scenarios/requirements.txt --refresh-package packse --upgrade
cargo dev fetch-python
source .env
./scripts/sync_scenarios.sh
```
2024-04-24 10:54:03 -05:00
konsti
c85c52d4ce
Unify packse find links urls (#2969)
The sync scenarios script is broken, so i did the updates manually

```
$ ./scripts/sync_scenarios.sh
Setting up a temporary environment...
Using Python 3.12.1 interpreter at: /home/konsti/projects/uv/.venv/bin/python3
Creating virtualenv at: .venv
Activate with: source .venv/bin/activate
  × No solution found when resolving dependencies:
  ╰─▶ Because docutils==0.21.post1 is unusable because the package metadata was inconsistent and you require docutils==0.21.post1, we can conclude that the requirements are unsatisfiable.

      hint: Metadata for docutils==0.21.post1 was inconsistent:
        Package metadata version `0.21` does not match given version `0.21.post1`
```

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
2024-04-11 08:35:22 +00:00
Zanie Blue
44e39bdca3
Replace Python bootstrapping script with Rust implementation (#2842)
See https://github.com/astral-sh/uv/issues/2617

Note this also includes:
- #2918 
- #2931 (pending)

A first step towards Python toolchain management in Rust.

First, we add a new crate to manage Python download metadata:

- Adds a new `uv-toolchain` crate
- Adds Rust structs for Python version download metadata
- Duplicates the script which downloads Python version metadata
- Adds a script to generate Rust code from the JSON metadata
- Adds a utility to download and extract the Python version

I explored some alternatives like a build script using things like
`serde` and `uneval` to automatically construct the code from our
structs but deemed it to heavy. Unlike Rye, I don't generate the Rust
directly from the web requests and have an intermediate JSON layer to
speed up iteration on the Rust types.

Next, we add add a `uv-dev` command `fetch-python` to download Python
versions per the bootstrapping script.

- Downloads a requested version or reads from `.python-versions`
- Extracts to `UV_BOOTSTRAP_DIR`
- Links executables for path extension

This command is not really intended to be user facing, but it's a good
PoC for the `uv-toolchain` API. Hash checking (via the sha256) isn't
implemented yet, we can do that in a follow-up.

Finally, we remove the `scripts/bootstrap` directory, update CI to use
the new command, and update the CONTRIBUTING docs.

<img width="1023" alt="Screenshot 2024-04-08 at 17 12 15"
src="57bd3cf1-7477-4bb8-a8e9-802a00d772cb">
2024-04-10 11:22:41 -05:00
Zanie Blue
bbe46c074c
Upgrade packse (#2963)
Should improve test performance with
https://github.com/astral-sh/packse/pull/169 thanks @konstin !
2024-04-10 09:30:57 -05:00
Zanie Blue
c345a79b9b
Add python-patch feature to isolate tests that require Python patch versions to match our suite (#2940)
Closes https://github.com/astral-sh/uv/issues/2165
Follows https://github.com/astral-sh/uv/pull/2930
2024-04-10 09:01:25 -05:00
Zanie Blue
d7ff8d93c0
Skip scenario tests on Windows (#2932)
These tests are about resolver correctness, which should not be platform
dependent and Windows CI is horribly slow.
2024-04-09 09:57:30 -05:00
Zanie Blue
20d4762776
Move scenario sync script to top-level scripts (#2788)
Same idea as https://github.com/astral-sh/uv/pull/2787
2024-04-02 23:27:05 +00:00
Zanie Blue
248d6f89ef
Bring harmony to the test snapshot filtering situation (#2678)
The snapshot filtering situation has gotten way out of hand, with each
test hand-rolling it's own filters on top of copied cruft from previous
tests.

I've attempted to address this holistically:

- `TestContext.filters()` has everything you should need 
- This was introduced a while ago, but needed a few more filters for it
to be generalized everywhere
- Using `INSTA_FILTERS` is **not recommended** unless you do not want
the context filters
    - It is okay to extend these filters for things unrelated to paths
- If you have to write a custom path filter, please highlight it in
review so we can address it in the common module
- `TestContext.site_packages()` gives cross-platform access to the
site-packages directory
    - Do not manually construct the path to site-packages from the venv
- Do not turn off tests on Windows because you manually constructed a
Unix path to site-packages
- `TestContext.workspace_root` gives access to uv's repository directory
    - Use this for installing from `scripts/packages/`
- If you need coverage for relative paths, copy the test package into
the `temp_dir` don't change the working directory of the test fixture

There is additional work that can be done here, such as:

- Auditing and removing additional uses of `INSTA_FILTERS`
- Updating manual construction of `Command` instances to use a utility
- The `venv` tests are particularly frightening in their lack of a test
context and could use some love
- Improving the developer experience i.e. apply context filters to
snapshots by default
2024-03-27 14:10:12 +00:00
konsti
79fbac7af5
Fast lint CI job: Rustfmt, Prettier, Ruff (#2406)
Add a single job for for fast lint tools. Rustfmt for rust, ruff for
python formatting and linting, prettier avoids inconsistent formatter
changes between pycharm and vscode.
2024-03-20 00:16:46 +00:00
Charlie Marsh
5a95f50619
Add support for PyTorch-style local version semantics (#2430)
## Summary

This PR adds limited support for PEP 440-compatible local version
testing. Our behavior is _not_ comprehensively in-line with the spec.
However, it does fix by _far_ the biggest practical limitation, and
resolves all the issues that've been raised on uv related to local
versions without introducing much complexity into the resolver, so it
feels like a good tradeoff for me.

I'll summarize the change here, but for more context, see [Andrew's
write-up](https://github.com/astral-sh/uv/issues/1855#issuecomment-1967024866)
in the linked issue.

Local version identifiers are really tricky because of asymmetry.
`==1.2.3` should allow `1.2.3+foo`, but `==1.2.3+foo` should not allow
`1.2.3`. It's very hard to map them to PubGrub, because PubGrub doesn't
think of things in terms of individual specifiers (unlike the PEP 440
spec) -- it only thinks in terms of ranges.

Right now, resolving PyTorch and friends fails, because...

- The user provides requirements like `torch==2.0.0+cu118` and
`torchvision==0.15.1+cu118`.
- We then match those exact versions.
- We then look at the requirements of `torchvision==0.15.1+cu118`, which
includes `torch==2.0.0`.
- Under PEP 440, this is fine, because `torch @ 2.0.0+cu118` should be
compatible with `torch==2.0.0`.
- In our model, though, it's not, because these are different versions.
If we change our comparison logic in various places to allow this, we
risk breaking some fundamental assumptions of PubGrub around version
continuity.
- Thus, we fail to resolve, because we can't accept both `torch @ 2.0.0`
and `torch @ 2.0.0+cu118`.

As compared to the solutions we explored in
https://github.com/astral-sh/uv/issues/1855#issuecomment-1967024866, at
a high level, this approach differs in that we lie about the
_dependencies_ of packages that rely on our local-version-using package,
rather than lying about the versions that exist, or the version we're
returning, etc.

In short:

- When users specify local versions upfront, we keep track of them. So,
above, we'd take note of `torch` and `torchvision`.
- When we convert the dependencies of a package to PubGrub ranges, we
check if the requirement matches `torch` or `torchvision`. If it's
an`==`, we check if it matches (in the above example) for
`torch==2.0.0`. If so, we _change_ the requirement to
`torch==2.0.0+cu118`. (If it's `==` some other version, we return an
incompatibility.)

In other words, we selectively override the declared dependencies by
making them _more specific_ if a compatible local version was specified
upfront.

The net effect here is that the motivating PyTorch resolutions all work.
And, in general, transitive local versions work as expected.

The thing that still _doesn't_ work is: imagine if there were _only_
local versions of `torch` available. Like, `torch @ 2.0.0` didn't exist,
but `torch @ 2.0.0+cpu` did, and `torch @ 2.0.0+gpu` did, and so on.
`pip install torch==2.0.0` would arbitrarily choose one one `2.0.0+cpu`
or `2.0.0+gpu`, and that's correct as per PEP 440 (local version
segments should be completely ignored on `torch==2.0.0`). However, uv
would fail to identify a compatible version. I'd _probably_ prefer to
fix this, although candidly I think our behavior is _ok_ in practice,
and it's never been reported as an issue.

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

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

Closes https://github.com/astral-sh/uv/issues/2328.
2024-03-16 10:24:50 -04:00
Charlie Marsh
bd3c577883
Update packse to pull in additional post tests (#2474) 2024-03-15 14:34:12 +00:00
Charlie Marsh
e69b76bc72
Make > operator exclude post and local releases (#2471)
## Summary

This PR attempts to use a similar trick to that we added in
https://github.com/astral-sh/uv/pull/1878, but for post-releases.

In https://github.com/astral-sh/uv/pull/1878, we added a fake "minimum"
version to enable us to treat `< 1.0.0` as _excluding_ pre-releases of
1.0.0.

Today, on `main`, we accept post-releases and local versions in `>
1.0.0`. But per PEP 440, that should _exclude_ post-releases and local
versions, unless the specifier is itself a pre-release, in which case,
pre-releases are allowed (e.g., `> 1.0.0.post0` should allow `>
1.0.0.post1`).

To support this, we add a fake "maximum" version that's greater than all
the post and local releases for a given version. This leverages our last
remaining free bit in the compact representation.
2024-03-15 14:02:06 +00:00
Charlie Marsh
fbb8bc1f6f
Pull in packse tests for post releases (#2468)
## Summary

Like local versions, a few of these failures and have fixups in the
generation script.
2024-03-14 23:26:31 +00:00
Charlie Marsh
17732246df
Update packse to pull in additional local version tests (#2462)
Precursor to #2430.
2024-03-14 20:13:47 +00:00
Zanie Blue
044a77cfd2
Simplify the packse scenario package name filters (#2440)
I liked the bird names but we can't actually apply those in some
situations (i.e. when the package is not supposed to exist) — this is
simpler.
2024-03-13 20:16:51 -05:00
Zanie Blue
104c74d911
Update packse development documentation to include --no-hash flag (#2437) 2024-03-13 19:33:42 -05:00
Zanie Blue
fd03362520
Use released packse for scenario updates (#2256)
- Now that `packse` is being published to PyPI we can install it from
there.
- Tweaks the tooling around scenario updates to manage a temporary
virtual environment for you.
- Makes use of a new index URL
- Includes local version segment scenarios (supersedes
https://github.com/astral-sh/uv/pull/2022)
2024-03-07 11:40:54 -06:00
Charlie Marsh
8d706b0f2a
Make < exclusive for non-prerelease markers (#1878)
## Summary

Even when pre-releases are "allowed", per PEP 440, `pydantic<2.0.0`
should _not_ include pre-releases. This PR modifies the specifier
translation to treat `pydantic<2.0.0` as `pydantic<2.0.0.min0`, where
`min` is an internal-only version segment that's invisible to users.

Closes https://github.com/astral-sh/uv/issues/1641.
2024-02-24 18:02:03 -05:00
Zanie Blue
f3ef55f879
Update the scenarios to use vendored build dependencies (#1605)
Uses `--find-links` to discover vendored scenario build dependencies and
allows us to use `--index-url` instead of `--extra-index-url` to avoid
hitting the real PyPI in scenario tests.
2024-02-19 21:55:03 +00:00
Charlie Marsh
f25781ff6c
Support recursive extras (#1435)
## Summary

We had a guard in the resolve to avoid "self-dependencies" (as in
`gps3==0.33.3`), but this guard was _unintentionally_ filtering out
recursive extras.

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

## Test Plan

Taken from https://github.com/astral-sh/uv/pull/1352.
2024-02-16 11:42:04 -05:00
Zanie Blue
0780afff95
Rename PUFFIN environment variables to UV (#1319)
A couple of these are actually user-facing although undocumented
2024-02-15 12:49:27 -06:00
Zanie Blue
2586f655bb
Rename to uv (#1302)
First, replace all usages in files in-place. I used my editor for this.
If someone wants to add a one-liner that'd be fun.

Then, update directory and file names:

```
# Run twice for nested directories
find . -type d -print0 | xargs -0 rename s/puffin/uv/g
find . -type d -print0 | xargs -0 rename s/puffin/uv/g

# Update files
find . -type f -print0 | xargs -0 rename s/puffin/uv/g
```

Then add all the files again

```
# Add all the files again
git add crates
git add python/uv

# This one needs a force-add
git add -f crates/uv-trampoline
```
2024-02-15 11:19:46 -06:00
Zanie Blue
e9e3e573a2
Report incompatible distributions to users (#1293)
Instead of dropping versions without a compatible distribution, we track
them as incompatibilities in the solver. This implementation follows
patterns established in https://github.com/astral-sh/puffin/pull/1290.

This required some significant refactoring of how we track incompatible
distributions. Notably:

- `Option<TagPriority>` is now `WheelCompatibility` which allows us to
track the reason a wheel is incompatible instead of just `None`.
- `Candidate` now has a `CandidateDist` with `Compatible` and
`Incompatibile` variants instead of just `ResolvableDist`; candidates
are not strictly compatible anymore
- `ResolvableDist` was renamed to `CompatibleDist`
- `IncompatibleWheel` was given an ordering implementation so we can
track the "most compatible" (but still incompatible) wheel. This allows
us to collapse the reason a version cannot be used to a single
incompatibility.
- The filtering in the `VersionMap` is retained, we still only store one
incompatible wheel per version. This is sufficient for error reporting.
- A `TagCompatibility` type was added for tracking which part of a wheel
tag is incompatible
- `Candidate::validate_python` moved to
`PythonRequirement::validate_dist`

I am doing more refactoring in #1298 — I think a couple passes will be
necessary to clarify the relationships of these types.

Includes improved error message snapshots for multiple incompatible
Python tag types from #1285 — we should add more scenarios for coverage
of behavior when multiple tags with different levels are present.
2024-02-15 10:48:15 -06:00