Commit Graph

407 Commits

Author SHA1 Message Date
Charlie Marsh 31bb01f0be
Ignore upper-bounds on `Requires-Python` (#4086)
## Summary

This PR modifies our `Requires-Python` handling to treat
`Requires-Python` as a lower bound. There's extensive discussion around
this in https://github.com/astral-sh/uv/issues/4022 and the references
linked therein. I think it's an experiment worth trying. Even in my own
small projects, I'm running into issues whereby I'm being "forced" to
add a `<4` upper bound to my `Requires-Python` due to these caps.

Separately, we should explore adding a mechanism that's distinct from
`Requires-Python` to enable users to declare a supported range for
locking.

Closes https://github.com/astral-sh/uv/issues/4022.
2024-06-06 13:52:57 -04:00
Charlie Marsh 30e73a60de
Avoid enforcing distribution ID uniqueness for extras (#4104)
## Summary

The condition enforced here isn't quite right. The same dependency can
appear multiple times, as long as the extra is different.

Closes https://github.com/astral-sh/uv/issues/4101.
2024-06-06 15:21:31 +00:00
Charlie Marsh 8798e91dd5
Avoid extra-only filtering for constraints (#4095)
## Summary

The "only include if relevant for the extra" filtering should _not_ be
applied to constraints. Otherwise, we'd only constrain when the extra
was included in the constraints file itself, which is incorrect.

Closes https://github.com/astral-sh/uv/issues/4091.
2024-06-06 13:58:46 +00:00
Charlie Marsh 120148f0a1
Remove integration tests from `uv-resolver` (#4083)
## Summary

I don't think it's worth maintaining this separate test harness for ~18
tests, when they can all be tested in the `uv` package itself. Let's
drop the maintenance burden.
2024-06-06 01:48:42 +00:00
Charlie Marsh 0acae9bd9c
Add support for development dependencies (#4036)
## Summary

Externally, development dependencies are currently structured as a flat
list of PEP 580-compatible requirements:

```toml
[tool.uv]
dev-dependencies = ["werkzeug"]
```

When locking, we lock all development dependencies; when syncing, users
can provide `--dev`.

Internally, though, we model them as dependency groups, similar to
Poetry, PDM, and [PEP 735](https://peps.python.org/pep-0735). This
enables us to change out the user-facing frontend without changing the
internal implementation, once we've decided how these should be exposed
to users.

A few important decisions encoded in the implementation (which we can
change later):

1. Groups are enabled globally, for all dependencies. This differs from
extras, which are enabled on a per-requirement basis. Note, however,
that we'll only discover groups for uv-enabled packages anyway.
2. Installing a group requires installing the base package. We rely on
this in PubGrub to ensure that we resolve to the same version (even
though we only expect groups to come from workspace dependencies anyway,
which are unique). But anyway, that's encoded in the resolver right now,
just as it is for extras.
2024-06-06 01:40:17 +00:00
Charlie Marsh 0b6d5b37dc
Enforce `Requires-Python` when syncing (#4068)
## Summary

Ensures that we raise if the user attempts to use a Python version that
wasn't included in the locked range.

Closes https://github.com/astral-sh/uv/issues/4052.
2024-06-05 16:22:08 -04:00
Charlie Marsh 642cef0dad
Track supported Python range in lockfile (#4065)
## Summary

This PR adds the `Requires-Python` range to the user's lockfile. This
will enable us to validate it when installing.

For now, we repeat the `Requires-Python` back to the user;
alternatively, though, we could detect the supported Python range
automatically.

See: https://github.com/astral-sh/uv/issues/4052
2024-06-05 16:21:59 -04:00
konsti 8596525d97
Update pubgrub to new `add_incompatibility_from_dependencies` (#4062)
We had previously changed the signature of
`DependencyProvider::get_dependencies` to return an iterator instead of
a hashmap to avoid the conversion cost from our dependencies `Vec` to
the pubgrub's hashmap. These changes are difficult to make in pubgrub
since they complicate the public api. But we don't actually use
`DependencyProvider::get_dependencies`, so we rolled those
customizations back in https://github.com/pubgrub-rs/pubgrub/pull/226
and instead opted to change only the internal
`add_incompatibility_from_dependencies` method that we exposed in our
fork. This aligns us closer with upstream, removes the design questions
about `DependencyProvider` from our concerns and reduces our diff (not
counting the github action) to +36 -12.
2024-06-05 20:46:00 +02:00
Charlie Marsh ae9610104a
Avoid dropping `pip sync` requirements with markers (#4051)
## Summary

Thankfully this is pretty rare since `pip sync` is usually run on `pip
compile` output, and `pip compile` never outputs markers.

Closes https://github.com/astral-sh/uv/issues/4044
2024-06-05 16:05:46 +00:00
Charlie Marsh 6d148da0ab
Preserve fragments when applying verbatim redirects (#4038)
## Summary

`echo
"git+https://github.com/pypa/sample-namespace-packages.git#subdirectory=pkg_resources/pkg_a"
| cargo run pip compile -` now resolves to a compliant URL.

Closes https://github.com/astral-sh/uv/issues/4037.
2024-06-05 03:53:23 +00:00
Charlie Marsh 27e5bfe397
Remove unnecessary requirements conversions (#4035) 2024-06-05 01:52:16 +00:00
Charlie Marsh 8de3e38b94
Read all extras directly from lockfile (#4033)
## Summary
We now pass `ExtrasSpecification` to the lock routine.
2024-06-05 01:03:55 +00:00
Charlie Marsh 57ea55d218
Add a hint for `Requires-Python` (#4021)
## Summary

As requested in the originating PR.
2024-06-04 16:52:15 -04:00
Charlie Marsh 420333a40e
Avoid 'are incompatible' for singular bounded versions (#4003)
## Summary

Not sure if this is worth the complexity, but it does read better.
2024-06-04 19:17:36 +00:00
Andrew Gallant 5c30b39fe3
uv-resolver: normalize marker expressions (#4017)
This is a quick fix for some flaky tests where the output in the lock
file isn't stable because marker expressions can be combined in a
non-deterministic order.

I believe there is ongoing work to simplify marker expressions which
will help here, but I think some kind of normalization is still
ultimately needed to guarantee consistent output.

I first noticed the flaky test in:
https://github.com/astral-sh/uv/pull/4015
2024-06-04 13:45:54 -04:00
Charlie Marsh 6afb659c9a
Respect `Requires-Python` in universal resolution (#3998)
## Summary

Closes #3982.
2024-06-04 13:56:08 +00:00
konsti 36f7fa3917
`impl TryFrom<&VersionSpecifiers> for PubGrubSpecifier` (#4010)
Add a missing utility conversion method from PEP 440 versions specifiers
to a pubgrub range.
2024-06-04 08:00:07 +00:00
Charlie Marsh 77e93157fb
Make target Python version an optional field (#4000)
## Summary

Instead of checking if the target and installed version are the same, we
model the data such that the target version is only present if it was
specified by the user. This also means that we correctly say "requested
version" even if the two happen to be the same.
2024-06-03 22:37:15 +00:00
Charlie Marsh ef43bcb233
Remove Python from available versions (#3996)
## Summary

I believe this is no longer necessary. Part of the problem here is that
we can't _know_ the full set of available Python versions, especially
once we start resolving against a `Requires-Python` rather than a fixed
set of two versions.
2024-06-03 20:11:45 +00:00
Charlie Marsh 10cd6b94c9
Normalize extras in lockfile (#3958)
## Summary

Previously, when we locked something like `flask[dotenv]`, we created
two separate distributions in the lockfile: one for `flask`, which
included the base dependencies, and one for `flask[dotenv]`, which
included the base dependencies _and_ the `dotenv` dependencies. This was
easy to implement, but it meant that we were duplicating all of the
distribution files for every extra, and duplicating all of the base
dependencies for every extra.

This PR normalizes the data such that we now have one entry per
distribution (i.e., `ExtraName` was removed from `DistributionId`), with
an optional dependencies table with an entry per extra, like:

```toml
[[distribution]]
name = "project"
version = "0.1.0"
source = "editable+file://[TEMP_DIR]/"
sdist = { url = "file://[TEMP_DIR]/" }

[[distribution.dependencies]]
name = "anyio"
version = "3.7.0"
source = "registry+https://pypi.org/simple"

[distribution.optional-dependencies]

[[distribution.optional-dependencies.test]]
name = "iniconfig"
version = "2.0.0"
source = "registry+https://pypi.org/simple"
```

This requires a bit more work upfront, because we now need to merge
multiple packages from the `PetGraph` representation when creating the
lockfile.

Closes https://github.com/astral-sh/uv/issues/3916.
2024-06-03 19:00:35 +00:00
Charlie Marsh 362b00cc12
Remove need to return Python version in `get_dependencies` (#3993)
## Summary

Once we use a _range_ rather than a precise version, it won't actually
make sense to return a version here. It's no longer required, so I'm
removing it.
2024-06-03 18:42:38 +00:00
Charlie Marsh 1a60368ce4
Use `PubGrubPython` type in Python incompatibility reporting (#3992)
## Summary

Rather than re-testing compatibility, I think we can just rely on the
types directly.
2024-06-03 14:32:22 -04:00
Charlie Marsh a23ca5bab7
Use universal resolution in `uv lock` (#3969)
## Summary

Wires up the optional markers in resolution, and adds
respecting-the-markers to `Lock:: to_resolution`.
2024-06-02 21:33:18 -04:00
Charlie Marsh c500b78936
Avoid re-adding solutions to forked state (#3967)
## Summary

Running a resolution that required forking was failing due to breaking
an invariant in PubGrub. It looks like we were adding the same
incompatibility multiple times, or something like that. The issue
appears to be that when forking, we modify the current state, then clone
it as the "next state", then push to the "forked states" -- but that
means we're cloning the _modified_ state.

This PR changes the order of operations such that we clone, then modify.
It shouldn't introduce any additional clones though.
2024-06-02 17:58:25 -04:00
Charlie Marsh 11324646cb
Remove some `anyhow` usages (#3962) 2024-06-01 20:11:23 +00:00
Charlie Marsh a70e33d947
Move reference check into `uv-git` (#3961) 2024-06-01 16:02:25 -04:00
Charlie Marsh c04a95e037
Respect resolved Git SHAs in `uv lock` (#3956)
## Summary

This PR ensures that if a lockfile already contains a resolved reference
(e.g., you locked with `main` previously, and it locked to a specific
commit), and you run `uv lock`, we use the same SHA, even if it's not
the latest SHA for that tag. This avoids upgrading Git dependencies
without `--upgrade`.

Closes #3920.
2024-06-01 12:40:11 +00:00
Charlie Marsh b7d77c04cc
Add Git resolver in lieu of static hash map (#3954)
## Summary

This PR removes the static resolver map:

```rust
static RESOLVED_GIT_REFS: Lazy<Mutex<FxHashMap<RepositoryReference, GitSha>>> =
    Lazy::new(Mutex::default);
```

With a `GitResolver` struct that we now pass around on the
`BuildContext`. There should be no behavior changes here; it's purely an
internal refactor with an eye towards making it cleaner for us to
"pre-populate" the list of resolved SHAs.
2024-05-31 22:44:42 -04:00
konsti 081f20c53e
Add support for `tool.uv` into distribution building (#3904)
With the change, we remove the special casing of workspace dependencies
and resolve `tool.uv` for all git and directory distributions. This
gives us support for non-editable workspace dependencies and path
dependencies in other workspaces. It removes a lot of special casing
around workspaces. These changes are the groundwork for supporting
`tool.uv` with dynamic metadata.

The basis for this change is moving `Requirement` from
`distribution-types` to `pypi-types` and the lowering logic from
`uv-requirements` to `uv-distribution`. This changes should be split out
in separate PRs.

I've included an example workspace `albatross-root-workspace2` where
`bird-feeder` depends on `a` from another workspace `ab`. There's a
bunch of failing tests and regressed error messages that still need
fixing. It does fix the audited package count for the workspace tests.
2024-05-31 02:42:03 +00:00
Ibraheem Ahmed 85183c1c36
Custom lock-file serialization (#3909)
## Summary

This PR changes the lock-file format to use inline tables for wheels and
source distributions, which currently use separate tables that make the
file harder to follow.

```diff
[[distribution]]
name = "typing-extensions"
version = "4.10.0"
source = "registry+https://pypi.org/simple"

- [distribution.sdist]
- url = "0d26ce356c7c323176620b7b483e44/typing_extensions-4.10.0.tar.gz"
- hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"
- size = 77558
-
- [[distribution.wheel]]
- url = "dc04a3ea60b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl"
- hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"
- size = 33926

+ sdist = { url = "0d26ce356c7c323176620b7b483e44/typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb", size = 77558 }
+ wheel = [{ url = "dc04a3ea60b9bc8074b5d6b7ab90bb/typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", size = 33926 }]
```

The downside is that the inline-tables end up quite long and TOML
doesn't support line breaks in inline tables, yet.

Part of https://github.com/astral-sh/uv/issues/3611.
2024-05-30 19:08:29 +00:00
Andrew Gallant d3b7d800ea uv-resolver: fix perf regression
We significantly regressed performance in some cases because we were
cloning the resolver state one more time than we needed to. That doesn't
sound like a lot, but in the case where there are no forks, it implies
we were cloning the state for every `get_dependencies` called when we
shouldn't have been cloning it at all.

Avoiding the clone results in somewhat tortured code. This can probably
be refactored by moving bits out to a helper routine, but that also
seemed non-trivial. So we let this suffice for now.
2024-05-30 14:23:14 -04:00
Andrew Gallant 17c043536b uv-resolver: thread markers through the resolver and into the lock file
This addresses the lack of marker support in prior commits.
Specifically, we add them as a new field to `AnnotatedDist`, and from
there, they get added to a `Distribution` in a `Lock`.
2024-05-30 14:23:14 -04:00
Andrew Gallant f865406ab4 uv-resolver: implement merging of forked resolutions
This commit is a pretty invasive change that implements the merging
of resolutions created by each fork of the resolver.

The main idea here is that each `SolveState` is converted into a
`Resolution` (a new type) and stored on the heap after its fork
completes. When all forks complete, they are all merged into a single
`Resolution`. This `Resolution` is then used to build a `ResolutionGraph`.

Construction of `ResolutionGraph` mostly stays the same (despite the
gnarly diff due to an indent change) with one exception: the code to
extract dependency edges out of PubGrub's state has been moved to
`SolveState::into_resolution`. The idea here is that once a fork
completes, we extract what we need from the PubGrub state and then
throw it away. We store these edges in our own intermediate type which
is then converted into petgraph edges in the `ResolutionGraph`
constructor.

One interesting change we make here is that our edge
data is now a `Version` instead of a `Range<Version>`. I don't think
`Range<Version>` was actually being used anywhere, so this seems okay?
In any case, I think `Version` here is correct because a resolution
corresponds to specific dependencies of each package. Moreover, I didn't
see an easy way to make things work with `Range<Version>`. Notably,
since we no longer have the guarantee that there is only one version of
each package, we need to use `(PackageName, Version)` instead of just
`PackageName` for inverted lookups in `ResolutionGraph::from_state`.

Finally, the main resolver loop itself is changed a bit to track all
forked resolutions and then merge them at the end.

Note that we don't really have any dealings with markers in this commit.
We'll get to that in a subsequent commit.
2024-05-30 14:23:14 -04:00
Andrew Gallant 9e977aa1be uv-resolver: slightly simplify ResolutionGraph::from_state
This changes the constructor to just take an `InMemoryIndex`
directly instead of the constituent parts. No real reason other
than it seems a little simpler.
2024-05-30 14:23:14 -04:00
Andrew Gallant 6f76a66510 uv-resolver: implement basic resolver forking
There are still some TODOs/FIXMEs here, but this makes represents a
chunk of the resolver refactoring to enable forking. We don't do any
merging of resolutions yet, so crucially, this code is broken when no
marker environment is provided. But when a marker environment is
provided, this should behave the same as a non-forking resolver. In
particular, `get_dependencies_forking` is just `get_dependencies`
whenever there's a marker environment.
2024-05-30 14:23:14 -04:00
Charlie Marsh 144566907e
Use lockfile versions as resolution preferences (#3921)
## Summary

Ensures that we avoid upgrading packages unless `--upgrade` or similar
is passed.

For now, the resolver only respects these for registry distributions.

Closes https://github.com/astral-sh/uv/issues/3918.
2024-05-30 17:59:53 +00:00
Charlie Marsh 502e04200d
Remove `from_registry_built_dist2` (#3922)
## Summary

I think this was left over from a prior refactor. (The existing
`from_registry_built_dist` was unused.)
2024-05-30 01:57:19 +00:00
Charlie Marsh 4859a27948
Add extra dependency annotations to lockfile and sync commands (#3913)
## Summary

This PR adds extras to the lockfile, and enables users to selectively
sync extras in `uv sync` and `uv run`. The end result here was fairly
simple, though it required a few refactors to get here. The basic idea
is that `DistributionId` now includes `extra: Option<ExtraName>`, so we
effectively treat extras as separate packages. Generating the lockfile,
and generating the resolution from the lockfile, fall out of this
naturally with no special-casing or additional changes.

The main downside here is that it bloats the lockfile significantly.
Specifically:

- We include _all_ distribution URLs and hashes for _every_ extra
variant.
- We include all dependencies for the extra variant, even though that
are dependencies of the base package.

We could normalize this representation by changing each distribution
have an `optional-dependencies` hash map that keys on extras, but we
actually don't have the information we need to create that right now
(specifically, we can't differentiate between dependencies that
_require_ the extra and dependencies on the base package).

Closes #3700.
2024-05-29 19:25:58 +00:00
Charlie Marsh 1bd5d8bc34
Include all extras when generating lockfile (#3912)
## Summary

This PR just ensures that when running `uv lock` (or `uv run`), we lock
with all extras. When we later install, we'll also _install_ with all
extras, but that will be changed in a future PR.
2024-05-29 15:08:20 -04:00
Charlie Marsh ed7f55606d
Split `requirements.txt`-style resolution distribution into its own type (#3911) 2024-05-29 16:48:28 +00:00
Charlie Marsh 19c91e7dac
Create distinct graph nodes for each package extra (#3908)
## Summary

Today, we represent each package as a single node in the graph, and
combine all the extras. This is helpful for the `requirements.txt`-style
resolution, in which we want to show each a single line for each package
with the extras combined into a single array.

This PR modifies the representation to instead use a separate node for
each (package, extra) pair. We then reduce into the previous format when
printing in the `requirements.txt`-style format, so there shouldn't be
any user-facing changes here.
2024-05-29 15:42:49 +00:00
Charlie Marsh 42b1ba04ec
Remove unused `PetGraph` weight (#3906) 2024-05-29 15:16:25 +00:00
Charlie Marsh cedd18e4c6
Remove some unused `pub` functions (#3872)
## Summary

I wrote a bad Python script to find these.
2024-05-28 15:58:13 +00:00
Charlie Marsh 1fc6a59707
Remove special-casing for editable requirements (#3869)
## Summary

There are a few behavior changes in here:

- We now enforce `--require-hashes` for editables, like pip. So if you
use `--require-hashes` with an editable requirement, we'll reject it. I
could change this if it seems off.
- We now treat source tree requirements, editable or not (e.g., both `-e
./black` and `./black`) as if `--refresh` is always enabled. This
doesn't mean that we _always_ rebuild them; but if you pass
`--reinstall`, then yes, we always rebuild them. I think this is an
improvement and is close to how editables work today.

Closes #3844.

Closes #2695.
2024-05-28 15:49:34 +00:00
Charlie Marsh 14fa49b7ba
Move availability enums into their own module (#3858) 2024-05-27 00:12:53 -04:00
Zanie Blue 31b0ff6373
Gate discovery of managed toolchains with preview (#3835)
Prepares for merge of https://github.com/astral-sh/uv/pull/3797, gating
managed toolchain discovery with the preview flag to lower risk of
releasing.

e.g.

```
❯ cargo dev -q fetch-python         
❯ cargo run -q -- venv --python 3.11
Using Python 3.11.9 interpreter at: /opt/homebrew/opt/python@3.11/bin/python3.11
Creating virtualenv at: .venv
Activate with: source .venv/bin/activate
❯ cargo run -q -- venv --preview --python 3.11
Using Python 3.11.7 interpreter at: /Users/zb/Library/Application Support/uv/toolchains/cpython-3.11.7-macos-aarch64-none/install/bin/python3
Creating virtualenv at: .venv
Activate with: source .venv/bin/activate
```

We'll add automatic fetching of managed interpreters later.
2024-05-27 04:05:19 +00:00
Ibraheem Ahmed 7dc322665c
Concurrent progress bars (#3252)
## Summary

Implements concurrent progress bars. Resolves
https://github.com/astral-sh/uv/issues/1209.

## Test Plan

https://github.com/astral-sh/uv/assets/34988408/b21bdfbb-8817-4873-a65c-16c9e8c7c460
2024-05-27 01:21:07 +00:00
Charlie Marsh 6682765630
Require pinned version in `Preference` type (#3828)
## Summary

This PR makes a variety of invalid states unrepresentable by changing
`Preference` to require a `PackageName` and `Version`, rather than
accepting a generic `Requirement`. There should be no meaningful
behavior changes.
2024-05-24 18:48:36 +00:00
Charlie Marsh 688f4f43d4
Ignore unnamed requirements in preferences (#3826)
## Summary

We actually _already_ ignore these (preferences only apply to versions,
not URLs), it just happens later on. This PR thus just avoids crashing.
The behavior is unchanged.

Closes #3822.
2024-05-24 17:32:20 +00:00
Charlie Marsh 999d072ae9
Always include package names for Git and HTTPS dependencies (#3821)
## Summary

Related to https://github.com/astral-sh/uv/issues/3818. We should
_always_ include the package name if we know it's not a file path, even
if it starts with an environment variable.
2024-05-24 14:01:38 +00:00
Charlie Marsh a9d9a6c13f
Incorporate build tag into wheel prioritization (#3781)
## Summary

It turns out that in the
[spec](https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention),
if a wheel filename includes a build tag, then we need to use it to
break ties. This PR implements that behavior. (Previously, we dropped
the build tag entirely.)

Closes #3779.

## Test Plan

Run: `cargo run pip install -i https://pypi.anaconda.org/intel/simple
mkl_fft==1.3.8 --python-platform linux --python-version 3.10`. This now
resolves without error. Previously, we selected build tag 63 of
`mkl_fft==1.3.8`, which led to an incompatibility with NumPy. Now, we
select build tag 70.
2024-05-23 21:12:53 +00:00
konsti 4db468e27f
Use `VerbatimParsedUrl` in `pep508_rs` (#3758)
When parsing requirements from any source, directly parse the url parts
(and reject unsupported urls) instead of parsing url parts at a later
stage. This removes a bunch of error branches and concludes the work
parsing url parts once and passing them around everywhere.

Many usages of the assembled `VerbatimUrl` remain, but these can be
removed incrementally.

Please review commit-by-commit.
2024-05-23 19:52:47 +00:00
Charlie Marsh 79fecdf251
Add a diagnostic trait (#3777) 2024-05-22 19:44:37 -04:00
Charlie Marsh 74c494d7dd
Report yanks for cached and resolved packages (#3772)
## Summary

We now show yanks as part of the resolution diagnostics, so they now
appear for `sync`, `install`, `compile`, and any other operations.
Further, they'll also appear for cached packages (but not packages that
are _already_ installed).

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

Closes #3766.
2024-05-22 21:21:37 +00:00
Charlie Marsh 0efc5d0cab
Reuse reporting operation in `venv` (#3755) 2024-05-22 15:43:20 -04:00
Charlie Marsh fe28b2c278
Remove unused methods from `Resolution` (#3754) 2024-05-22 18:48:44 +00:00
Charlie Marsh 0313e7d78b
Use common routines for `pip install` and `pip sync` (#3737)
## Summary

This PR takes the functions used in `pip install`, moves them into a
common module, and then replaces all the `pip sync` logic with calls
into those functions. The net effect is that `pip install` and `pip
sync` share far more code and demonstrate much more consistent behavior.

Closes https://github.com/astral-sh/uv/issues/3555.
2024-05-22 12:15:17 -04:00
Charlie Marsh e398444f2f
Track editable requirements in lockfile (#3725)
## Summary

This PR adds editables using a new source type (`editable+...`), and
then extracts the editables from the lockfile in `uv sync`.

Closes https://github.com/astral-sh/uv/issues/3695.
2024-05-22 09:06:18 -04:00
Zanie Blue d540d0f28b
Rewrite Python interpreter discovery (#3266)
Updates our Python interpreter discovery to conform to the rules
described in #2386, please see that issue for a full description of the
behavior. Briefly, we now will search for interpreters that satisfy a
requested version without stopping at the first Python executable.
Additionally, if retrieving information about an interpreter fails we
will continue to search for a working interpreter. We also add the
plumbing necessary to request Python implementations other than CPython,
though we do not add support for other implementations at this time.

A major internal goal of this work is to prepare for user-facing managed
toolchains i.e. fetching a requested version during `uv run`. These APIs
are not introduced, but there is some managed toolchain handling as
required for our test suite.

Some noteworthy implementation changes:

- The `uv_interpreter::find_python` module has been removed in favor of
a `uv_interpreter::discovery` module.
- There are new types to help structure interpreter requests and track
sources
- Executable discovery is implemented as a big lazy iterator and is a
central authority for source precedence
- `uv_interpreter::Error` variants were split into scoped types in each
module
- There's much more unit test coverage, but not for Windows yet

Remaining work:

- [x] Write new test cases
- [x] Determine correct behavior around executables in the current
directory
- _Future_: Combine `PythonVersion` and `VersionRequest`
- _Future_: Consider splitting `ManagedToolchain` into local and remote
variants
- _Future_: Add Windows unit test coverage
- _Future_: Explore behavior around implementation precedence (i.e.
CPython over PyPy)

Refactors split into:

- #3329 
- #3330 
- #3331
- #3332

Closes #2386
2024-05-21 14:37:23 -05:00
Zanie Blue c14a7dbef3
Improve display of root package in range errors (#3711)
Instead of saying 

> we can conclude that you require==0a0.dev0 and
pandas-stubs==2.0.3.230814 are incompatible.

we'll say

> we can conclude that your requirements and pandas-stubs==2.0.3.230814
are incompatible.

Closes #3710 

I'm not sure how to get unit test coverage for this, might look into
that. Ideally we'd skip this branch entirely?
2024-05-21 19:28:23 +00:00
konsti 95af1db0bb
Let `RequirementSource::Path.editable` be `bool`, not `Option<bool>` (#3693)
Small refactoring of the internal representation. This does not change
`tool.uv.sources`.
2024-05-21 14:34:43 +00:00
konsti 76418f5bdf
Arc-wrap `PubGrubPackage` for cheap cloning in pubgrub (#3688)
Pubgrub stores incompatibilities as (package name, version range)
tuples, meaning it needs to clone the package name for each
incompatibility, and each non-borrowed operation on incompatibilities.
https://github.com/astral-sh/uv/pull/3673 made me realize that
`PubGrubPackage` has gotten large (expensive to copy), so like `Version`
and other structs, i've added an `Arc` wrapper around it.

It's a pity clippy forbids `.deref()`, it's less opaque than `&**` and
has IDE support (clicking on `.deref()` jumps to the right impl).

## Benchmarks

It looks like this matters most for complex resolutions which, i assume
because they carry larger `PubGrubPackageInner::Package` and
`PubGrubPackageInner::Extra` types.

```bash
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/jupyter.in" "./uv-branch pip compile -q ./scripts/requirements/jupyter.in"
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/airflow.in" "./uv-branch pip compile -q ./scripts/requirements/airflow.in"
hyperfine --warmup 5 "./uv-main pip compile -q ./scripts/requirements/boto3.in" "./uv-branch pip compile -q ./scripts/requirements/boto3.in"
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/jupyter.in
  Time (mean ± σ):      18.2 ms ±   1.6 ms    [User: 14.4 ms, System: 26.0 ms]
  Range (min … max):    15.8 ms …  22.5 ms    181 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/jupyter.in
  Time (mean ± σ):      17.8 ms ±   1.4 ms    [User: 14.4 ms, System: 25.3 ms]
  Range (min … max):    15.4 ms …  23.1 ms    159 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/jupyter.in ran
    1.02 ± 0.12 times faster than ./uv-main pip compile -q ./scripts/requirements/jupyter.in
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/airflow.in
  Time (mean ± σ):     153.7 ms ±   3.5 ms    [User: 165.2 ms, System: 157.6 ms]
  Range (min … max):   150.4 ms … 163.0 ms    19 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/airflow.in
  Time (mean ± σ):     123.9 ms ±   4.6 ms    [User: 152.4 ms, System: 133.8 ms]
  Range (min … max):   118.4 ms … 138.1 ms    24 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/airflow.in ran
    1.24 ± 0.05 times faster than ./uv-main pip compile -q ./scripts/requirements/airflow.in
```

```
Benchmark 1: ./uv-main pip compile -q ./scripts/requirements/boto3.in
  Time (mean ± σ):     327.0 ms ±   3.8 ms    [User: 344.5 ms, System: 71.6 ms]
  Range (min … max):   322.7 ms … 334.6 ms    10 runs

Benchmark 2: ./uv-branch pip compile -q ./scripts/requirements/boto3.in
  Time (mean ± σ):     311.2 ms ±   3.1 ms    [User: 339.3 ms, System: 63.1 ms]
  Range (min … max):   307.8 ms … 317.0 ms    10 runs

Summary
  ./uv-branch pip compile -q ./scripts/requirements/boto3.in ran
    1.05 ± 0.02 times faster than ./uv-main pip compile -q ./scripts/requirements/boto3.in
```

<!--
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?
-->
2024-05-21 13:49:35 +02:00
Charlie Marsh 49f0e84f3d
Write relative paths with unnamed requirement syntax (#3682)
## Summary

This PR falls back to writing an unnamed requirement if it appears to be
a relative URL. pip is way more flexible when providing an unnamed
requirement than when providing a PEP 508 requirement. For example,
_only_ this works:

```
black @ file:///Users/crmarsh/workspace/uv/scripts/packages/black_editable
```

Any other form will fail.

Meanwhile, _all_ of these work:

```
file:///Users/crmarsh/workspace/uv/scripts/packages/black_editable
scripts/packages/black_editable
./scripts/packages/black_editable
file:./scripts/packages/black_editable
file:scripts/packages/black_editable
```

Closes https://github.com/astral-sh/uv/issues/3180.
2024-05-20 21:22:06 -04:00
Charlie Marsh 0362918196
Evaluate arbitrary markers to `false` (#3681)
## Summary

See: https://github.com/astral-sh/uv/pull/3679#issuecomment-2121387428.

Closes: https://github.com/astral-sh/uv/issues/3675 (although I think we
have another improvement to make there -- will file separately).
2024-05-21 01:01:11 +00:00
Andrew Gallant 776a7e47f3 uv-resolver: add `Option<MarkerTree>` to `PubGrubPackage`
This just adds the field to the type and always sets it to `None`. There
are semantic changes in this commit.

Closes #3359
2024-05-20 19:56:24 -04:00
Andrew Gallant 1ed3555bf0 uv-resolver: sort in `format_terms`
This makes use of the newly added `Ord` impl on `PubGrubPackage` to make
the output of `format_terms` independent of hashmap iteration order.

This was already collecting the terms into an intermediate `Vec`, so
sorting probably isn't going to add any significant overhead here.
(Plus, this is only running when formatting an error message after a
solution could not be found, so an extra sort doesn't seem like a big
deal here.)

Note that some tests are updated in this commit as a result of this
change. As far as I can tell, the semantic meaning of the output remains
the same. But the order of the listed packages does not.

Specific thing motivating this change is, in a subsequent, I added
`Option<MarkerTree>` to `PubGrubPackage::Package`, and this caused
similar changes in test output. So I backtracked and isolated this
change from the addition of `Option<MarkerTree>`.
2024-05-20 19:56:24 -04:00
Andrew Gallant 976bc9ba0e uv-resolver: make PubGrubPackage orderable
It turns out that we use PubGrubPackage as the key in hashmaps in a fair
few places. And when we iterate over hashmaps, the order is unspecified.
This can in turn result in changes in output as a result of changes in
the PubGrubPackage definition, purely as a function of its changing
hash. This is confusing as there should be no semantic difference.

Thus, this is a precursor to introducing some more determinism to places
I found in the error reporting whose output depending on hashmap
iteration order.
2024-05-20 19:56:24 -04:00
Andrew Gallant 9f109f243c uv-resolver: remove 'derive(Derivative)' from PubGrubPackage
It looks like the last vestiges of `Derivative` were removed in commit
7eaed07f6c, but the then rendered
superfluous `derive(Derivative)` wasn't removed.
2024-05-20 19:56:24 -04:00
Andrew Gallant eac8221718 uv-resolver: use named fields for some PubGrubPackage variants
I'm planning to add another field here (markers), which puts a lot of
stress on the positional approach. So let's just switch over to named
fields.
2024-05-20 19:56:24 -04:00
konsti 95c9621541
Refactor editables for supporting them in bluejay commands (#3639)
This is split out from workspaces support, which needs editables in the
bluejay commands. It consists mainly of refactorings:

* Move the `editable` module one level up.
* Introduce a `BuiltEditableMetadata` type for `(LocalEditable,
Metadata23, Requirements)`.
* Add editables to `InstalledPackagesProvider` so we can use
`EmptyInstalledPackages` for them.
2024-05-20 16:22:12 +00:00
Charlie Marsh f3965fef5e
Use filename trait for `WheelWire` conversion (#3651)
## Summary

The main motivation here is that the `.filename()` method that we
implement on `Url` will do URL decoding for the last segment, which we
were missing here.

The errors are a bit awkward, because in
`crates/uv-resolver/src/lock.rs`, we wrap in `failed to extract filename
from URL: {url}`, so in theory we want the underlying errors to _omit_
the URL? But sometimes they use `#[error(transparent)]`?
2024-05-20 09:25:31 -04:00
Charlie Marsh 657eebd50b
Remove `SourceDistFilename` from `RegistrySourceDist` (#3650)
## Summary

Uncertain about this, but we don't actually need the full
`SourceDistFilename`, only the name and version -- and we often have
that information already (as in the lockfile routines). So by flattening
the fields onto `RegistrySourceDist`, we can avoid re-parsing for
information we already have.
2024-05-20 09:25:23 -04:00
Charlie Marsh 1124df9bc5
Remove subdirectory from direct wheel URL type (#3667)
## Summary

Closes #3665.
2024-05-20 02:01:57 +00:00
Charlie Marsh 0718705c21
Track parsed Git URL components in `GitSourceUrl` (#3656)
## Summary

Closes https://github.com/astral-sh/uv/issues/3571.
2024-05-20 00:43:30 +00:00
Charlie Marsh a0745d0d9d
Add registry file size to lockfile (#3652)
## Summary

Mentioned in #3611.
2024-05-19 02:27:05 +00:00
Charlie Marsh 18b095ce28
Make `from_rev` take an owned value (#3631)
## Summary

We always clone internally, and in most case we're already passing
`&String`.
2024-05-18 17:26:15 +00:00
Charlie Marsh 47f4114a1b
Add registry source distribution support to lockfile (#3649)
## Summary

One TODO but going to resolve that separately.
2024-05-18 16:54:27 +00:00
Charlie Marsh fe2bc079bc
Use `ParsedGitUrl` to recreate Git source kind URL (#3647) 2024-05-17 21:45:46 +00:00
Charlie Marsh e2d7d2026b
Add direct URL conversion to lockfile (#3633)
## Summary

Similar to #3630, but for direct URL distributions (for both wheels and
source distributions).
2024-05-17 21:32:42 +00:00
Charlie Marsh 0d512be46c
Support lossless serialization for Git dependencies in lockfile (#3630)
## Summary

This PR adds lossless deserialization for `GitSourceDist` distributions
in the lockfile. Specifically, we now properly preserve the requested
revision, the subdirectory, and the precise Git commit SHA.

## Test Plan

`cargo test`
2024-05-17 21:23:40 +00:00
Ibraheem Ahmed 0f67a6ceea
Use `FxHasher` in resolver (#3641)
## Summary

We can use `FxHasher` in a few more places for string and version keys.
This gives a consistent ~2% improvement to warm resolves.
2024-05-17 15:04:22 -04:00
Ibraheem Ahmed 39af09f09b
Parallelize resolver (#3627)
## Summary

This PR introduces parallelism to the resolver. Specifically, we can
perform PubGrub resolution on a separate thread, while keeping all I/O
on the tokio thread. We already have the infrastructure set up for this
with the channel and `OnceMap`, which makes this change relatively
simple. The big change needed to make this possible is removing the
lifetimes on some of the types that need to be shared between the
resolver and pubgrub thread.

A related PR, https://github.com/astral-sh/uv/pull/1163, found that
adding `yield_now` calls improved throughput. With optimal scheduling we
might be able to get away with everything on the same thread here.
However, in the ideal pipeline with perfect prefetching, the resolution
and prefetching can run completely in parallel without depending on one
another. While this would be very difficult to achieve, even with our
current prefetching pattern we see a consistent performance improvement
from parallelism.

This does also require reverting a few of the changes from
https://github.com/astral-sh/uv/pull/3413, but not all of them. The
sharing is isolated to the resolver task.

## Test Plan

On smaller tasks performance is mixed with ~2% improvements/regressions
on both sides. However, on medium-large resolution tasks we see the
benefits of parallelism, with improvements anywhere from 10-50%.

```
./scripts/requirements/jupyter.in
Benchmark 1: ./target/profiling/baseline (resolve-warm)
  Time (mean ± σ):      29.2 ms ±   1.8 ms    [User: 20.3 ms, System: 29.8 ms]
  Range (min … max):    26.4 ms …  36.0 ms    91 runs
 
Benchmark 2: ./target/profiling/parallel (resolve-warm)
  Time (mean ± σ):      25.5 ms ±   1.0 ms    [User: 19.5 ms, System: 25.5 ms]
  Range (min … max):    23.6 ms …  27.8 ms    99 runs
 
Summary
  ./target/profiling/parallel (resolve-warm) ran
    1.15 ± 0.08 times faster than ./target/profiling/baseline (resolve-warm)
```
```
./scripts/requirements/boto3.in   
Benchmark 1: ./target/profiling/baseline (resolve-warm)
  Time (mean ± σ):     487.1 ms ±   6.2 ms    [User: 464.6 ms, System: 61.6 ms]
  Range (min … max):   480.0 ms … 497.3 ms    10 runs
 
Benchmark 2: ./target/profiling/parallel (resolve-warm)
  Time (mean ± σ):     430.8 ms ±   9.3 ms    [User: 529.0 ms, System: 77.2 ms]
  Range (min … max):   417.1 ms … 442.5 ms    10 runs
 
Summary
  ./target/profiling/parallel (resolve-warm) ran
    1.13 ± 0.03 times faster than ./target/profiling/baseline (resolve-warm)
```
```
./scripts/requirements/airflow.in 
Benchmark 1: ./target/profiling/baseline (resolve-warm)
  Time (mean ± σ):     478.1 ms ±  18.8 ms    [User: 482.6 ms, System: 205.0 ms]
  Range (min … max):   454.7 ms … 508.9 ms    10 runs
 
Benchmark 2: ./target/profiling/parallel (resolve-warm)
  Time (mean ± σ):     308.7 ms ±  11.7 ms    [User: 428.5 ms, System: 209.5 ms]
  Range (min … max):   287.8 ms … 323.1 ms    10 runs
 
Summary
  ./target/profiling/parallel (resolve-warm) ran
    1.55 ± 0.08 times faster than ./target/profiling/baseline (resolve-warm)
```
2024-05-17 11:47:30 -04:00
Ahmed Ilyas e3e7895605
Fix source annotation in pip compile `annotation-style=line` output (#3637)
## Summary

Fixes a small discrepancy between the pip compile outputs for
`annotation-style=split` and `annotation-style=line` commands.

### Problem

Consider the following `pyproject.toml` file.
```sh
$ cat pyproject.toml
[project]
name = "uv_test"
dynamic = ["version"]
dependencies = ["click"]
```

Running uv pip compile with annotation-style=split on uv 0.1.44 version
yields the following:
```sh
❯ uv pip compile pyproject.toml --annotation-style=split
Resolved 1 package in 2ms
# This file was autogenerated by uv via the following command:
#    uv pip compile pyproject.toml --annotation-style=split
click==8.1.7
    # via uv-test (pyproject.toml)
```

However, running uv pip compile with annotation-style=line doesn't
include source info for root level dependencies.
```sh
❯ uv pip compile pyproject.toml --annotation-style=line
Resolved 1 package in 1ms
# This file was autogenerated by uv via the following command:
#    uv pip compile pyproject.toml --annotation-style=line
click==8.1.7
```

With this PR:
```sh
❯ ../target/debug/uv pip compile --annotation-style=line pyproject.toml
Resolved 1 package in 6ms
# This file was autogenerated by uv via the following command:
#    uv pip compile --annotation-style=line pyproject.toml
click==8.1.7              # via uv-test (pyproject.toml)
```

This also now matches `pip-tools` output:
```sh
❯ pip-compile --annotation-style=line pyproject.toml
#
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
#    pip-compile --annotation-style=line pyproject.toml
#
click==8.1.7              # via uv_test (pyproject.toml)

```

## Test Plan

`cargo test`
2024-05-17 09:57:11 -04:00
Andrew Gallant 0a055b7942
distribution-types: allow RegistrySourceDist to have wheels attached to it (#3610)
Following from #3595, we'd like wheels to make their way into the lock
file even if the current environment selects an sdist. With #3595, this
didn't happen:

$ cargo run -p uv -- pip compile -p3.10 <(echo psycopg2)
--unstable-uv-lock-file
    $ cat uv.lock
    version = 1

    [[distribution]]
    name = "psycopg2"
    version = "2.9.9"
    source = "registry+https://pypi.org/simple"

    [distribution.sdist]
url =
"dc6acaf46d76fce95daac5e0f0301b/psycopg2-2.9.9.tar.gz"
hash =
"sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"

The above example uses `psycopg2`, which has an sdist and wheels only on
Windows. Since I ran the above on Linux, an sdist was selected. But no
wheels appeared in the lock file.

With this PR, wheels are now correctly plumbed through:

$ cargo run -p uv -- pip compile -p3.10 <(echo psycopg2)
--unstable-uv-lock-file
    $ cat uv.lock
    version = 1

    [[distribution]]
    name = "psycopg2"
    version = "2.9.9"
    source = "registry+https://pypi.org/simple"

    [distribution.sdist]
url =
"dc6acaf46d76fce95daac5e0f0301b/psycopg2-2.9.9.tar.gz"
hash =
"sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"

    [[distribution.wheel]]
url =
"2767d96391f5cde90b82cb3e8c2a12/psycopg2-2.9.9-cp310-cp310-win32.whl"
hash =
"sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"

    [[distribution.wheel]]
url =
"6572dec6831f85491a5e4dda606a98/psycopg2-2.9.9-cp310-cp310-win_amd64.whl"
hash =
"sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"

    [[distribution.wheel]]
url =
"1fc5b9d33c858a602868a592cdc1b0/psycopg2-2.9.9-cp311-cp311-win32.whl"
hash =
"sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"

    [[distribution.wheel]]
url =
"5133dd3183e671b278ce248810b7f7/psycopg2-2.9.9-cp311-cp311-win_amd64.whl"
hash =
"sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"

    [[distribution.wheel]]
url =
"f74ffe6b6fe119ccb8a6546c3fb893/psycopg2-2.9.9-cp312-cp312-win32.whl"
hash =
"sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"

    [[distribution.wheel]]
url =
"c4a26e1918ab7ee854fb5247f16c40/psycopg2-2.9.9-cp312-cp312-win_amd64.whl"
hash =
"sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"

    [[distribution.wheel]]
url =
"ffeb9ac356ce0d6c4f2f34e396dbc0/psycopg2-2.9.9-cp37-cp37m-win32.whl"
hash =
"sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"

    [[distribution.wheel]]
url =
"0a39176d36fd7105774e57996f63cd/psycopg2-2.9.9-cp37-cp37m-win_amd64.whl"
hash =
"sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"

    [[distribution.wheel]]
url =
"86b90d30c4420cc3c0f6da2b8f3a9a/psycopg2-2.9.9-cp38-cp38-win32.whl"
hash =
"sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"

    [[distribution.wheel]]
url =
"c439b378ef79997a935f10374f3c0d/psycopg2-2.9.9-cp38-cp38-win_amd64.whl"
hash =
"sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"

    [[distribution.wheel]]
url =
"5080c0e61ad5f08b9503e508aac116/psycopg2-2.9.9-cp39-cp39-win32.whl"
hash =
"sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"

    [[distribution.wheel]]
url =
"ec73fe66d4d65f5bbe54efb191d9e6/psycopg2-2.9.9-cp39-cp39-win_amd64.whl"
hash =
"sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"

Ref #3351
2024-05-15 15:16:00 -04:00
Andrew Gallant 018a7150d6
uv-distribution: include all wheels in distribution types (#3595)
Our current flow of data from "simple registry package" to "final
resolved distribution" goes through a number of types:

* `SimpleMetadata` is the API response from a registry that includes all
published versions for a package. Each version has an assortment of
metadata
associated with it.
* `VersionFiles` is the aforementioned metadata. It is split in two: a
group of files for source distributions and a group of files for wheels.
* `PrioritizedDist` collects a subset of the files from `VersionFiles`
to form a selection of the "best" sdist and the "best" wheel for the
current environment.
* `CompatibleDist` is created from a borrowed `PrioritizedDist` that,
perhaps among other things, encapsulates the decision of whether to pick
an sdist or a wheel. (This decision depends both on compatibility and
the action being performed. e.g., When doing installation, a
`CompatibleDist` will sometimes select an sdist over a wheel.)
* `ResolvedDistRef` is like a `ResolvedDist`, but borrows a `Dist`.
* `ResolvedDist` is the almost-final-form of a distribution in a
resolution and is created from a `ResolvedDistRef`.
* `AnnotatedResolvedDist` is a new data type that is the actual final
form of a distribution that a universal lock file cares about. It
bundles a `ResolvedDist` with some metadata needed to generate a lock
file.

One of the requirements of a universal lock file is that we include all
wheels (and maybe all source distributions? but at least one if it's
present) associated with a distribution. But the above flow of data (in
the step from `VersionFiles` to `PrioritizedDist`) drops all wheels
except for the best one.

To remedy this, in this PR, we rejigger `PrioritizedDist`,
`CompatibleDist` and `ResolvedDistRef` so that all wheel data is
preserved. And when a `ResolvedDistRef` is finally turned into a
`ResolvedDist`, we copy all of the wheel data. And finally, we adjust
the `Lock` constructor to read this new data and include it in the lock
file. To make this work, we also modify `RegistryBuiltDist` so that it
can contain one or more wheels instead of just one.

One shortcoming here (called out in the code as a FIXME) is that if a
source distribution is selected as the "best" thing to use (perhaps
there are no compatible wheels), then the wheels won't end up in the
lock file. I plan to fix this in a follow-up PR.

We also aren't totally consistent on source distribution naming.
Sometimes we use `sdist`. Sometimes `source`. Sometimes `source_dist`.
I think it'd be nice to just use `sdist` everywhere, but I do prefer
the type names to be `SourceDist`. And sometimes you want function
names to match the type names (i.e., `from_source_dist`), which in turn
leads to an appearance of inconsistency. I'm open to ideas.

Closes #3351
2024-05-15 15:07:28 -04:00
Ibraheem Ahmed a962a65302
Add routine for verifying two marker trees are disjoint (#3583)
## Summary

Implements https://github.com/astral-sh/uv/issues/3355.
2024-05-15 13:01:05 -04:00
Charlie Marsh d0c6b0a93e
Add local path conversions from lockfile (#3609)
## Summary

Just does the most basic thing to convert from `Distribution` back to
the installable type.
2024-05-15 12:46:45 -04:00
Charlie Marsh 55aedda379
Separate cache construction from initialization (#3607)
## Summary

Ensures that we only initialize the cache for commands that require it.

Closes https://github.com/astral-sh/uv/issues/3539.
2024-05-15 12:29:39 -04:00
Charlie Marsh 647f38be31
Add missing `"directory"` branch in source match (#3608)
## Summary

Just my oversight.
2024-05-15 16:25:55 +00:00
Charlie Marsh d76b023cd6
Remove `resolve_cli.rs` and `resolve_many.rs` (#3606)
## Summary

These depend on some APIs that I want to be internal-only for the
resolver crate, and we're no longer using them.
2024-05-15 16:04:47 +00:00
Charlie Marsh 85c71d6987
Rename `pinned_package` to `dist` (#3598) 2024-05-15 00:42:27 +00:00
Charlie Marsh 9a18d4ff46
Split `resolution.rs` into multiple files (#3597)
## Summary

No code changes.
2024-05-15 00:16:04 +00:00
Charlie Marsh 8971944a01
Move `extras` onto annotated distribution (#3592)
## Summary

Like hashes, we can now store these on `AnnotatedDist` rather than
creating a parallel hash map and performing lookups later on.
2024-05-14 23:25:06 +00:00
Charlie Marsh c7348589fa
Remove some editable branches in resolution (#3591)
## Summary

Editables should always go down the `Some(url)` branch.
2024-05-14 23:16:06 +00:00
Charlie Marsh 4a42730cae
Add hashes and versions to all distributions (#3589)
## Summary

In `ResolutionGraph::from_state`, we have mechanisms to grab the hashes
and metadata for all distributions -- but we then throw that information
away. This PR preserves it on a new `AnnotatedDist` (yikes, open to
suggestions) that wraps `ResolvedDist` and includes (1) the hashes
(computed or from the registry) and (2) the `Metadata23`, which lets us
extract the version.

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

Closes https://github.com/astral-sh/uv/issues/3357.
2024-05-14 23:07:24 +00:00
Charlie Marsh 7363f31ceb
Rename `sourcedist` to `sdist` in lockfile (#3590)
## Summary

I think this is more consistent with Brett's proposal and looks more
natural to me as a user. What do you think, @BurntSushi?
2024-05-14 16:56:00 -04:00
Charlie Marsh f4cd7d627a
Split extra validation from graph construction (#3586)
## Summary

Splits this into two loops that each handle independent cases, to make
the code a little easier to reason about. No behavioral or logic changes
-- just splitting the `match` across two loops.
2024-05-14 16:41:16 -04:00
Charlie Marsh 27c8c5ad44
Explain hash tie-breaking in distribution comparisons (#3581) 2024-05-14 13:34:32 -04:00
Ibraheem Ahmed 8ce9051296
Parse marker tree before evaluation (#3520)
## Summary

Parse `MarkerTree` expressions upfront, instead of lazily during
evaluation.

This makes implementing https://github.com/astral-sh/uv/issues/3355 a
lot easier.
2024-05-14 11:02:30 -04:00
konsti 025368965e
Reduce `GitSourceDist` URL usage (#3458)
Refactor the easy-to-remove usage of the `VerbatimUrl` on
`GitSourceDist`
2024-05-14 02:03:55 +00:00
konsti b263fcff9c
Preserve parsed url in ResolvedDist -> Requirement (#3457)
Lose less information in the `ResolvedDist` -> `Requirement` conversion.
2024-05-14 01:47:20 +00:00
konsti a24124571a
Use the term path instead of local file consistently (#3430)
Rename `ParsedLocalFileUrl` to `ParsedPathUrl`, eliminating the term
`LocalFile` in favor of path.
2024-05-14 01:35:52 +00:00
konsti 0010954ca7
Add parsed URL to `PubGrubPackage` (#3426)
Avoid reparsing urls by storing the parsed parts across resolution on
`PubGrubPackage`.

Part 1 of #3408
2024-05-14 00:55:21 +00:00
Charlie Marsh 8cec217eff
Avoid attempting to build editables when fetching metadata (#3563)
## Summary

If we see an editable as a dependency, we currently attempt to fetch its
metadata, when we shouldn't.

Closes https://github.com/astral-sh/uv/issues/3562.
2024-05-14 00:03:53 +00:00
Charlie Marsh 44363d25c2
Respect constraints on editable dependencies (#3554)
## Summary

Ensures that constraints are enforced for editable requirements.

Closes #3548.
2024-05-13 17:06:27 +00:00
Charlie Marsh 10ec48299e
Add a `PubGrubRequirement` struct (#3553)
## Summary

Formalize some of the patterns in here. No behavior changes, just moving
this method onto a struct.
2024-05-13 16:59:10 +00:00
Charlie Marsh eb8e733790
Rename "constraints" to "dependencies" in resolver (#3552)
## Summary

It's confusing that we use `constraints` here because constraints mean
something else for us (e.g., `--constraint constraints.txt`). These are
really the dependencies of a given `PubGrubPackage` -- the type is even
called `PubGrubDependencies`.
2024-05-13 16:30:16 +00:00
Charlie Marsh 42c3bfa351
Make `Directory` its own distribution kind (#3519)
## Summary

I think this is overall good change because it explicitly encodes (in
the type system) something that was previously implicit. I'm not a huge
fan of the names here, open to input.

It covers some of https://github.com/astral-sh/uv/issues/3506 but I
don't think it _closes_ it.
2024-05-13 10:03:14 -04:00
Dimitri Papadopoulos Orfanos d2ee567fe7
Fix a few typos found by codespell (#3543)
<!--
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

Just fix typos.

While `alpha-numeric` is not really a misspelling:
- it is missing from mainstream curated dictionaries, all of them
suggest `alphanumeric`;
- it is less used than `alphanumeric` (more than ⨉10 less) according to
the Google [Ngram
Viewer](https://books.google.com/ngrams/graph?content=alpha-numeric%2Calphanumeric&year_start=1900&year_end=2019&corpus=en-2019);
- it is [missing from
SCOWL](http://app.aspell.net/lookup?dict=en_US-large;words=alpha-numeric).

## Test Plan

CI jobs.
2024-05-13 11:55:10 +00:00
Charlie Marsh c2452957f9
Remove unused dependencies (#3527)
Surfaced with `cargo shear`.
2024-05-11 13:33:49 -04:00
Ibraheem Ahmed 783df8f657
Consolidate concurrency limits (#3493)
## Summary

This PR consolidates the concurrency limits used throughout `uv` and
exposes two limits, `UV_CONCURRENT_DOWNLOADS` and
`UV_CONCURRENT_BUILDS`, as environment variables.

Currently, `uv` has a number of concurrent streams that it buffers using
relatively arbitrary limits for backpressure. However, many of these
limits are conflated. We run a relatively small number of tasks overall
and should start most things as soon as possible. What we really want to
limit are three separate operations:
- File I/O. This is managed by tokio's blocking pool and we should not
really have to worry about it.
- Network I/O.
- Python build processes.

Because the current limits span a broad range of tasks, it's possible
that a limit meant for network I/O is occupied by tasks performing
builds, reading from the file system, or even waiting on a `OnceMap`. We
also don't limit build processes that end up being required to perform a
download. While this may not pose a performance problem because our
limits are relatively high, it does mean that the limits do not do what
we want, making it tricky to expose them to users
(https://github.com/astral-sh/uv/issues/1205,
https://github.com/astral-sh/uv/issues/3311).

After this change, the limits on network I/O and build processes are
centralized and managed by semaphores. All other tasks are unbuffered
(note that these tasks are still bounded, so backpressure should not be
a problem).
2024-05-10 12:43:08 -04:00
Andrew Gallant eab2b832a6
uv-resolver: make hashes optional (#3505)
This only makes hashes optional for wheels/sdists that come from
registires or direct URLs. For wheels/sdists that come from other
sources, a hash should not be present.

For path dependencies, a hash should not be present because the state of
the path dependency is not intended to be tracked in the lock file. This
is consistent with how other tools deal with path dependencies, and if
it were otherwise, the hash would I believe need to be updated for every
change to the path dependency.

For git dependencies (source dists only), a hash should not be present
because the lock will contain the specific commit revision hash. This is
functionally equivalent to a hash, and so a hash is redundant.

As part of this change, we validate the presence or absence of a hash
based on the dependency source. We also add our first regression tests.
2024-05-10 10:32:30 -04:00
Andrew Gallant ad01a768bc
uv-resolver: push resolver state to its own type (#3492)
This still keeps the resolver state on the stack, but it organizes it
into a more structured representation. This is a precursor to
implementing resolver forking, where we will ultimately put this state
on the heap. The idea is that this will let us maintain multiple
independent resolver states that will all produce their own resolution
(and potentially other forked states).

Closes #3354
2024-05-09 14:16:43 -04:00
Andrew Gallant 7d67b7bb49 pep508: un-export fields for MarkerEnvironment
We now use the getters and setters everywhere.

There were some places where we wanted to build a `MarkerEnvironment`
out of whole cloth, usually in tests. To facilitate those use cases, we
add a `MarkerEnvironmentBuilder` that provides a convenient constructor.
It's basically like a `MarkerEnvironment::new`, but with named
parameters. That's useful here because there are so many fields (and
they many have the same type).
2024-05-09 10:06:02 -04:00
Andrew Gallant 8b0fad3560 uv-resolver: make MarkerEnvironment optional
This commit touches a lot of code, but the conceptual change here is
pretty simple: make it so we can run the resolver without providing a
`MarkerEnvironment`. This also indicates that the resolver should run in
universal mode. That is, the effect of a missing marker environment is
that all marker expressions that reference the marker environment are
evaluated to `true`. That is, they are ignored. (The only markers we
evaluate in that context are extras, which are the only markers that
aren't dependent on the environment.)

One interesting change here is that a `Resolver` no longer needs an
`Interpreter`. Previously, it had only been using it to construct a
`PythonRequirement`, by filling in the installed version from the
`Interpreter` state. But we now construct a `PythonRequirement`
explicitly since its `target` Python version should no longer be tied to
the `MarkerEnvironment`. (Currently, the marker environment is mutated
such that its `python_full_version` is derived from multiple sources,
including the CLI, which I found a touch confusing.)

The change in behavior can now be observed through the
`--unstable-uv-lock-file` flag. First, without it:

```
$ cat requirements.in
anyio>=4.3.0 ; sys_platform == "linux"
anyio<4 ; sys_platform == "darwin"
$ cargo run -qp uv -- pip compile -p3.10 requirements.in
anyio==4.3.0
exceptiongroup==1.2.1
    # via anyio
idna==3.7
    # via anyio
sniffio==1.3.1
    # via anyio
typing-extensions==4.11.0
    # via anyio
```

And now with it:

```
$ cargo run -qp uv -- pip compile -p3.10 requirements.in --unstable-uv-lock-file
  x No solution found when resolving dependencies:
  `-> Because you require anyio>=4.3.0 and anyio<4, we can conclude that the requirements are unsatisfiable.
```

This is expected at this point because the marker expressions are being
explicitly ignored, *and* there is no forking done yet to account for
the conflict.
2024-05-09 09:24:37 -04:00
Charlie Marsh f16cbfda7e
Add a dedicated struct for source annotations (#3478) 2024-05-09 04:40:35 +00:00
Tom Parker-Shemilt bc963d13cb
Annotate sources of requirements (#3269)
## Summary

Fixes https://github.com/astral-sh/uv/issues/1343. This is kinda a first
draft at the moment, but does at least mostly work locally (barring some
bits of the test suite that seem to not work for me in general).

## Test Plan

Mostly running the existing tests and checking the revised output is
sane

## Outstanding issues

Most of these come down to "AFAIK, the existing tools don't support
these patterns, but `uv` does" and so I'm not sure there's an existing
good answer here! Most of the answers so far are "whatever was easiest
to build"

- [x] ~~Is "-r pyproject.toml" correct? Should it show something else or
get skipped entirely~~ No it wasn't. Fixed in
3044fa8b86
- [ ] If the requirements file is stdin, that just gets skipped. Should
it be recorded?
- [ ] Overrides get shown as "--override<override.txt>". Correct?
- [x] ~~Some of the tests (e.g.
`dependency_excludes_non_contiguous_range_of_compatible_versions`) make
assumptions about the order of package versions being outputted, which
this PR breaks. I'm not sure if the text is fairly arbitrary and can be
replaced or whether the behaviour needs fixing?~~ - fixed by removing
the custom pubgrub PartialEq/Hash
- [ ] Are all the `TrackedFromStr` et al changes needed, or is there an
easier way? I don't think so, I think it's necessary to track these sort
of things fairly comprehensively to make this feature work, and this
sort of invasive change feels necessary, but happy to be proved wrong
there :)
- [x] ~~If you have a requirement coming in from two or more different
requirements files only one turns up. I've got a closed-source example
for this (can go into more detail if needed), mostly consisting of a
complicated set of common deps creating a larger set. It's a rarer case,
but worth considering.~~ 042432b200
- [ ] Doesn't add annotations for `setup.py` yet
- This is pretty hard, as the correct location to insert the path is
`crates/pypi-types/src/metadata.rs`'s `parse_pkg_info`, which as it's
based off a source distribution has entirely thrown away such matters as
"where did this package requirement get built from". Could add "`built
package name`" as a dep, but that's a little odd.
2024-05-08 23:19:22 -04:00
Charlie Marsh 7c6632114b
Improve JSON Schema and add export script (#3461)
## Summary

A few errors I noticed after generating the schema.
2024-05-08 16:15:16 +00:00
konsti 1ad6aa8a23
Use generic pubgrub incompatibility reason (#3335)
Pubgrub got a new feature where all unavailability is a custom, instead
of the reasonless `UnavailableDependencies` and our custom `String` type
previously (https://github.com/pubgrub-rs/pubgrub/pull/208). This PR
introduces a `UnavailableReason` that tracks either an entire version
being unusable, or a specific version. The error messages now also track
this difference properly.

The pubgrub commit is our main rebased onto the merged
https://github.com/pubgrub-rs/pubgrub/pull/208, i'll push
`konsti/main-rebase-generic-reason` to `main` after checking for rebase
problems.
2024-05-08 08:40:15 +00:00
Ibraheem Ahmed 94cf604574
Remove unnecessary uses of `DashMap` and `Arc` (#3413)
## Summary

All of the resolver code is run on the main thread, so a lot of the
`Send` bounds and uses of `DashMap` and `Arc` are unnecessary. We could
also switch to using single-threaded versions of `Mutex` and `Notify` in
some places, but there isn't really a crate that provides those I would
be comfortable with using.

The `Arc` in `OnceMap` can't easily be removed because of the uv-auth
code which uses the
[reqwest-middleware](https://docs.rs/reqwest-middleware/latest/reqwest_middleware/trait.Middleware.html)
crate, that seems to adds unnecessary `Send` bounds because of
`async-trait`. We could duplicate the code and create a `OnceMapLocal`
variant, but I don't feel that's worth it.
2024-05-06 22:30:43 -04:00
konsti 2c84af15b8
Rename `distribution_types::VersionOrUrl` to `VersionOrUrlRef` (#3254)
This is more consistent with the other `*Ref` types and reduces
confusion with the real `VersionOrUrl` type.
2024-05-06 14:15:56 -04:00
konsti 098944fc7d
Improve non-git error message (#3403)
The boxing changes are due to clippy
2024-05-06 13:28:05 +02:00
konsti d0c3146ef6
Restore verbatim in error message (#3402)
Fixup for
https://github.com/astral-sh/uv/pull/3263#discussion_r1589718035
2024-05-06 11:17:06 +00:00
konsti 9de49c8a60
Make pubgrub an allowed ident (#3399)
Followup to #3361, fix some backtick-quoting.
2024-05-06 09:10:37 +00:00
konsti 4f87edbe66
Add basic `tool.uv.sources` support (#3263)
## Introduction

PEP 621 is limited. Specifically, it lacks
* Relative path support
* Editable support
* Workspace support
* Index pinning or any sort of index specification

The semantics of urls are a custom extension, PEP 440 does not specify
how to use git references or subdirectories, instead pip has a custom
stringly format. We need to somehow support these while still stying
compatible with PEP 621.

## `tool.uv.source`

Drawing inspiration from cargo, poetry and rye, we add `tool.uv.sources`
or (for now stub only) `tool.uv.workspace`:

```toml
[project]
name = "albatross"
version = "0.1.0"
dependencies = [
  "tqdm >=4.66.2,<5",
  "torch ==2.2.2",
  "transformers[torch] >=4.39.3,<5",
  "importlib_metadata >=7.1.0,<8; python_version < '3.10'",
  "mollymawk ==0.1.0"
]

[tool.uv.sources]
tqdm = { git = "https://github.com/tqdm/tqdm", rev = "cc372d09dcd5a5eabdc6ed4cf365bdb0be004d44" }
importlib_metadata = { url = "https://github.com/python/importlib_metadata/archive/refs/tags/v7.1.0.zip" }
torch = { index = "torch-cu118" }
mollymawk = { workspace = true }

[tool.uv.workspace]
include = [
  "packages/mollymawk"
]

[tool.uv.indexes]
torch-cu118 = "https://download.pytorch.org/whl/cu118"
```

See `docs/specifying_dependencies.md` for a detailed explanation of the
format. The basic gist is that `project.dependencies` is what ends up on
pypi, while `tool.uv.sources` are your non-published additions. We do
support the full range or PEP 508, we just hide it in the docs and
prefer the exploded table for easier readability and less confusing with
actual url parts.

This format should eventually be able to subsume requirements.txt's
current use cases. While we will continue to support the legacy `uv pip`
interface, this is a piece of the uv's own top level interface. Together
with `uv run` and a lockfile format, you should only need to write
`pyproject.toml` and do `uv run`, which generates/uses/updates your
lockfile behind the scenes, no more pip-style requirements involved. It
also lays the groundwork for implementing index pinning.

## Changes

This PR implements:
* Reading and lowering `project.dependencies`,
`project.optional-dependencies` and `tool.uv.sources` into a new
requirements format, including:
  * Git dependencies
  * Url dependencies
  * Path dependencies, including relative and editable
* `pip install` integration
* Error reporting for invalid `tool.uv.sources`
* Json schema integration (works in pycharm, see below)
* Draft user-level docs (see `docs/specifying_dependencies.md`)

It does not implement:
* No `pip compile` testing, deprioritizing towards our own lockfile
* Index pinning (stub definitions only)
* Development dependencies
* Workspace support (stub definitions only)
* Overrides in pyproject.toml
* Patching/replacing dependencies

One technically breaking change is that we now require user provided
pyproject.toml to be valid wrt to PEP 621. Included files still fall
back to PEP 517. That means `pip install -r requirements.txt` requires
it to be valid while `pip install -r requirements.txt` with `-e .` as
content falls back to PEP 517 as before.

## Implementation

The `pep508` requirement is replaced by a new `UvRequirement` (name up
for bikeshedding, not particularly attached to the uv prefix). The still
existing `pep508_rs::Requirement` type is a url format copied from pip's
requirements.txt and doesn't appropriately capture all features we
want/need to support. The bulk of the diff is changing the requirement
type throughout the codebase.

We still use `VerbatimUrl` in many places, where we would expect a
parsed/decomposed url type, specifically:
* Reading core metadata except top level pyproject.toml files, we fail a
step later instead if the url isn't supported.
* Allowed `Urls`.
* `PackageId` with a custom `CanonicalUrl` comparison, instead of
canonicalizing urls eagerly.
* `PubGrubPackage`: We eventually convert the `VerbatimUrl` back to a
`Dist` (`Dist::from_url`), instead of remembering the url.
* Source dist types: We use verbatim url even though we know and require
that these are supported urls we can and have parsed.

I tried to make improve the situation be replacing `VerbatimUrl`, but
these changes would require massive invasive changes (see e.g.
https://github.com/astral-sh/uv/pull/3253). A main problem is the ref
`VersionOrUrl` and applying overrides, which assume the same
requirement/url type everywhere. In its current form, this PR increases
this tech debt.

I've tried to split off PRs and commits, but the main refactoring is
still a single monolith commit to make it compile and the tests pass.

## Demo

Adding
d1ae3b85d5/pyproject.json
as json schema (v7) to pycharm for `pyproject.toml`, you can try the IDE
support already:


![pycharm](https://github.com/astral-sh/uv/assets/6826232/599082c7-6be5-41c1-a3cd-516092382f8d)


[dove.webm](https://github.com/astral-sh/uv/assets/6826232/c293c272-c80b-459d-8c95-8c46a8d198a1)
2024-05-03 21:10:50 +00:00
samypr100 2ffb252498
Update Rust to v1.78 (#3361)
## Summary

Updates rust to 1.78 in `rust-toolchain.toml`

See: https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html

### Potential blockers

* homebre still on 1.77 -
https://github.com/Homebrew/homebrew-core/pull/170649
* conda-forge still on 1.77 - https://anaconda.org/conda-forge/rust
2024-05-03 20:07:13 +00:00
Andrew Gallant 1089abda3f
require serde and rkyv everywhere; remove optional serde and rkyv features (#3345)
In *some* places in our crates, `serde` (and `rkyv`) are optional
dependencies. I believe this was done out of reasons of "good sense,"
that is, it follows a Rust ecosystem pattern where serde integration
tends to be an opt-in crate feature. (And similarly for `rkyv`.)

However, ultimately, `uv` itself requires `serde` and `rkyv` to
function. Since our crates are strictly internal, there are limited
consumers for our crates without `serde` (and `rkyv`) enabled. I think
one possibility is that optional `serde` (and `rkyv`) integration means
that someone can do this:

    cargo test -p pep440_rs

And this will run tests _without_ `serde` or `rkyv` enabled. That in
turn could lead to faster iteration time by reducing compile times. But,
I'm not sure this is worth supporting. The iterative compilation times
of
individual crates are probably fast enough in debug mode, even with
`serde` and `rkyv` enabled. Namely, `serde` and `rkyv` themselves
shouldn't need to be re-compiled in most cases. On `main`:

```
from-scratch: `cargo test -p pep440_rs --lib` 0.685
incremental: `cargo test -p pep440_rs --lib` 0.278s
from-scratch: `cargo test -p pep440_rs --features serde,rkyv --lib` 3.948s
incremental: `cargo test -p pep440_rs --features serde,rkyv --lib` 0.321s
```

So while a from-scratch build does take significantly longer, an
incremental build is about the same.

The benefit of doing this change is two-fold:

1. It brings out crates into alignment with "reality." In particular,
   some crates were _implicitly_ relying on `serde` being enabled
   without explicitly declaring it. This technically means that our
   `Cargo.toml`s were wrong in some cases, but it is hard to observe it
   because of feature unification in a Cargo workspace.
2. We no longer need to deal with the cognitive burden of writing
   `#[cfg_attr(feature = "serde", ...)]` everywhere.
2024-05-03 10:21:03 -04:00
Andrew Gallant 7772e6249f
add basic "install from lock file" operation (#3340)
This PR principally adds a routine for converting a `Lock` to a
`Resolution`, where a `Resolution` is a map of package names pinned to
a specific version.

I'm not sure that a `Resolution` is ultimately what we want here (we
might need more stuff), but this was the quickest route I could find to
plug a `Lock` into our existing `uv pip install` infrastructure.

This commit also does a little refactoring of the `Lock` types. The
main thing is to permit extra state on some of the types (like a
`by_id` map on `Lock` for quick lookups of distributions) that aren't
included in the serialization format of a `Lock`. We achieve this
by defining separate `Wire` types that are automatically converted
to-and-from via `serde`.

Note that like with the lock file format types themselves, we leave a
few `todo!()` expressions around. The main idea is to get something
minimally working without spending too much effort here. (A fair bit
of refactoring will be required to generate a lock file, and it's
not clear how much this code will wind up needing to change anyway.)
In particular, we only handle the case of installing wheels from a
registry.

A demonstration of the full flow:

```
$ requirements.in
anyio
$ cargo run -p uv -- pip compile -p3.10 requirements.in --unstable-uv-lock-file
$ uv venv
$ cargo run -p uv -- pip install --unstable-uv-lock-file anyio -r requirements.in
Installed 5 packages in 7ms
 + anyio==4.3.0
 + exceptiongroup==1.2.1
 + idna==3.7
 + sniffio==1.3.1
 + typing-extensions==4.11.0
```

In order to install from a lock file, we start from the root and do a
breadth first traversal over its dependencies. We aren't yet filtering
on marker expressions (since they aren't in the lock file yet), but we
should be able to add that in the future. In so doing, the traversal
should select only the subset of distributions relevant for the current
platform.
2024-05-03 08:18:36 -04:00
Ibraheem Ahmed c5cd808876
Remove uncondtional `serde` usage in uv-resolver (#3317)
## Summary

Makes the `serde` implementations added in https://github.com/astral-sh/uv/pull/3314 conditional on uv-resolver's `serde` feature.
2024-04-29 16:31:37 -04:00
Andrew Gallant d2e7c0554b
uv-resolver: add initial version of universal lock file format (#3314)
This is meant to be a base on which to build. There are some parts
which are implicitly incomplete and others which are explicitly
incomplete. The latter are indicated by TODO comments.

Here is a non-exhaustive list of incomplete things. In many cases, these
are incomplete simply because the data isn't present in a
`ResolutionGraph`. Future work will need to refactor our resolver so
that this data is correctly passed down.

* Not all wheels are included. Only the "selected" wheel for the current
  distribution is included.
* Marker expressions are always absent.
* We don't emit hashes for certainly kinds of distributions (direct
  URLs, git, and path).
* We don't capture git information from a dependency specification.
  Right now, we just always emit "default branch."

There are perhaps also other changes we might want to make to the format
of a more cosmetic nature. Right now, all arrays are encoded using
whatever the `toml` crate decides to do. But we might want to exert more
control over this. For example, by using inline tables or squashing more
things into strings (like I did for `Source` and `Hash`). I think the
main trade-off here is that table arrays are somewhat difficult to read
(especially without indentation), where as squashing things down into a
more condensed format potentially makes future compatible additions
harder.

I also went pretty light on the documentation here than what I would
normally do. That's primarily because I think this code is going to
go through some evolution and I didn't want to spend too much time
documenting something that is likely to change.

Finally, here's an example of the lock file format in TOML for the
`anyio` dependency. I generated it with the following command:

```
cargo run -p uv -- pip compile -p3.10 ~/astral/tmp/reqs/anyio.in --unstable-uv-lock-file
```

And that writes out a `uv.lock` file:

```toml
version = 1

[[distribution]]
name = "anyio"
version = "4.3.0"
source = "registry+https://pypi.org/simple"

[[distribution.wheel]]
url = "2f20c40b45242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl"
hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"

[[distribution.dependencies]]
name = "exceptiongroup"
version = "1.2.1"
source = "registry+https://pypi.org/simple"

[[distribution.dependencies]]
name = "idna"
version = "3.7"
source = "registry+https://pypi.org/simple"

[[distribution.dependencies]]
name = "sniffio"
version = "1.3.1"
source = "registry+https://pypi.org/simple"

[[distribution.dependencies]]
name = "typing-extensions"
version = "4.11.0"
source = "registry+https://pypi.org/simple"

[[distribution]]
name = "exceptiongroup"
version = "1.2.1"
source = "registry+https://pypi.org/simple"

[[distribution.wheel]]
url = "79fe92dd414cadab75055b0ae00b33/exceptiongroup-1.2.1-py3-none-any.whl"
hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"

[[distribution]]
name = "idna"
version = "3.7"
source = "registry+https://pypi.org/simple"

[[distribution.wheel]]
url = "741d8c8280948df2ea0eda2c8b79e8/idna-3.7-py3-none-any.whl"
hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"

[[distribution]]
name = "sniffio"
version = "1.3.1"
source = "registry+https://pypi.org/simple"

[[distribution.wheel]]
url = "75a9c94214239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"
hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"

[[distribution]]
name = "typing-extensions"
version = "4.11.0"
source = "registry+https://pypi.org/simple"

[[distribution.wheel]]
url = "936e2092671b43269810cd589ceaf5/typing_extensions-4.11.0-py3-none-any.whl"
hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"
```
2024-04-29 14:03:17 -04:00
Yorick 43181f1933
Implement `--index-strategy unsafe-best-match` (#3138)
## Summary

This index strategy resolves every package to the latest possible
version across indexes. If a version is in multiple indexes, the first
available index is selected.

Implements #3137 

This closely matches pip.

## Test Plan

Good question. I'm hesitant to use my certifi example here, since that
would inevitably break when torch removes this package. Please comment!
2024-04-27 01:24:54 +00:00
Ibraheem Ahmed 20e9589662
Combine dependency clauses with the same root (#3225)
## Summary

Simplifies dependency errors of the form `you require package-a and you
require package-b` to `you require package-a and package-b`. Resolves
https://github.com/astral-sh/uv/issues/1009.
2024-04-24 12:34:32 -04:00
Andrew Gallant 0b84eb0140
once-map: avoid hard-coding `Arc` (#3242)
The only thing a `OnceMap` really needs to be able to do with the value
is to clone it. All extant uses benefited from having this done for them
by automatically wrapping values in an `Arc`. But this isn't necessarily
true for all things. For example, a value might have an `Arc` internally
to making cloning cheap in other contexts, and it doesn't make sense to
re-wrap it in an `Arc` just to use it with a `OnceMap`. Or
alternatively, cloning might just be cheap enough on its own that an
`Arc` isn't worth it.
2024-04-24 11:11:46 -04:00
Charlie Marsh 84989a3f49
Unroll self-dependencies via extras (#3230)
## Summary

We now recursively expand any self-dependencies via extras, which lets
us detect conflicts sooner and avoid building unnecessary versions of
packages that are excluded via the extra.

Closes https://github.com/astral-sh/uv/issues/3135.
2024-04-24 07:51:56 -04:00
konsti bed730571d
Fix single crate tokio features (#3234)
Previously, uv-auth would fail to compile due to a missing process
feature. I chose to make all tokio features we use top level features,
so we can share the tokio cache between all test invocations.
2024-04-24 08:55:15 +00:00
Charlie Marsh 8b711d2e4d
Avoid adding extras when expanding constraints (#3232)
## Summary

See the diff in the tests. If you have a constraint with an extra, we
should respect it, but we shouldn't _add_ the extra to the requirements.
2024-04-24 02:00:27 +00:00
Charlie Marsh 14f05f27b3
Add ticks around error messages more consistently (#3004)
## Summary

I found some of these too bare (e.g., when they _just_ show a package
name with no other information). For me, this makes it easier to
differentiate error message copy from data. But open to other opinions.
Take a look at the fixture changes and LMK!
2024-04-22 23:58:36 +00:00
Charlie Marsh 792a917a97
Restrict observed requirements to direct when `--no-deps` is specified (#3191)
## Summary

This PR avoids: (1) using the lookahead resolver when `--no-deps` is
specified (we'll never use those requirements), and (2) including any
transitive requirements when searching for allowed URLs, etc., when
`--no-deps` is specified.

Closes https://github.com/astral-sh/uv/issues/3183.
2024-04-22 17:17:58 +00:00
Charlie Marsh a4f125ca34
Avoid waiting for metadata for `--no-deps` editables (#3188)
## Summary

We don't emit a request for this, so we shouldn't wait for it either --
we already have the metadata!

Closes https://github.com/astral-sh/uv/issues/3184.
2024-04-22 16:29:19 +00:00
konsti 82c4772e89
Move unnamed requirements to their own pep508_rs module and requirements-txt (#3186)
Another refactoring in preparation of using a richer requirements type.
No functional changes, only moves code around
2024-04-22 14:02:39 +00:00
Charlie Marsh fda378fd29
Avoid preferring constrained over unconstrained packages (#3148)
## Summary

pip prefers somewhat-constrained over unconstrained packages... but only
if they're at equal depths in the tree. We don't have a way to track the
latter property yet (I've added a TODO), so for now, we should remove
this constraint -- it seems to be counter-productive.

I've filed https://github.com/astral-sh/uv/issues/3149 as a follow-up.

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

## Test Plan

- `git clone https://github.com/drivendataorg/zamba.git`
- `cat "-e .[tests]" > req.in`
- `cargo run venv && cargo run pip compile req.in --refresh -n
--python-platform linux --python-version 3.8`
2024-04-19 23:30:08 +00:00
Charlie Marsh a241bc79b1
Add priorities for editables (#3133)
## Summary

We weren't setting a priority for editables, so they were being visited
last.

I think there's still a problem whereby we're not aggressive enough in
visiting recursive extras (and, in fact, that's making it really hard to
write a test -- I wrote a test, but the most-reduced case still fails,
and I'd need to add a layer of indirection to make it
fail-on-main-but-pass-on-this-branch), but that problem likely already
existed on main prior to #3087, so I just want to get this quick fix out
now.

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

## Test Plan

- `git clone https://github.com/cda-tum/mqt-core.git`
- `cargo run venv`
- `cargo run pip install 'scikit-build-core[pyproject]>=0.8.1'
'setuptools_scm>=7' 'pybind11>=2.12' --resolution=lowest-direct`
- `cargo run pip install --no-build-isolation
'-ve.[test,qiskit,evaluation,coverage]' --resolution=lowest-direct`
2024-04-19 02:04:58 +00:00
Charlie Marsh 2e88bb6f1b
Add a proxy layer for extras (#3100)
Given requirements like:

```
black==23.1.0
black[colorama]
```

The resolver will (on `main`) add a dependency on Black, and then try to
use the most recent version of Black to satisfy `black[colorama]`. For
sake of example, assume `black==24.0.0` is the most recent version. Once
the selects this most recent version, it'll fetch the metadata, then
return the dependencies for `black==24.0.0` with the `colorama` extra
enabled. Finally, it will tack on `black==24.0.0` (a dependency on the
base package). The resolver will then detect a conflict between
`black==23.1.0` and `black==24.0.0`, and throw out
`black[colorama]==24.0.0`, trying to next most-recent version.

This is both wasteful and can cause problems, since we're fetching
metadata for versions that will _never_ satisfy the resolver. In the
`apache-airflow[all]` case, I also ran into an issue whereby we were
attempting to build very old versions of `apache-airflow` due to
`apache-airflow[pandas]`, which in turn led to resolution failures.

The solution proposed here is that we create a new proxy package with
exactly two dependencies: one on `black` and one of `black[colorama]`.
Both of these packages must be at the same version as the proxy package,
so the resolver knows much _earlier_ that (in the above example) the
extra variant _must_ match `23.1.0`.
2024-04-19 01:04:59 +00:00
Chan Kang 8c7d0a31e6
Hide password in the index printed via `--emit-index-annotation` (#3112)
## Summary

resolves https://github.com/astral-sh/uv/issues/3106

## Test Plan

added a simple test where the password provided in `UV_INDEX_URL` is
hidden in the output as expected.
2024-04-18 03:59:44 +00:00
Charlie Marsh 7fb2bf816f
Add JSON Schema support (#3046)
## Summary

This PR adds JSON Schema support. The setup mirrors Ruff's own.
2024-04-17 17:24:41 +00:00
Charlie Marsh b456fa2939
Incorporate heuristics to improve package prioritization (#3087)
See: https://github.com/astral-sh/uv/issues/3078
2024-04-17 14:21:42 +00:00
konsti d1b07a3f49
Log versions tried from batch prefetch (#3090)
This is required for evaluating #3087.

This also removes tracking of virtual packages from extras from the
batch prefetcher (we only track real packages).

Let's look at some stats:
* jupyter: Tried 100 versions: anyio 1, argon2-cffi 1,
argon2-cffi-bindings 1, arrow 1, asttokens 1, async-lru 1, attrs 1,
babel 1, beautifulsoup4 1, bleach 1, certifi 1, cffi 1,
charset-normalizer 1, comm 1, debugpy 1, decorator 1, defusedxml 1,
exceptiongroup 1, executing 1, fastjsonschema 1, fqdn 1, h11 1, httpcore
1, httpx 1, idna 1, ipykernel 1, ipython 1, ipywidgets 1, isoduration 1,
jedi 1, jinja2 1, json5 1, jsonpointer 1, jsonschema 1,
jsonschema-specifications 1, jupyter 1, jupyter-client 1,
jupyter-console 1, jupyter-core 1, jupyter-events 1, jupyter-lsp 1,
jupyter-server 1, jupyter-server-terminals 1, jupyterlab 1,
jupyterlab-pygments 1, jupyterlab-server 1, jupyterlab-widgets 1,
markupsafe 1, matplotlib-inline 1, mistune 1, nbclient 1, nbconvert 1,
nbformat 1, nest-asyncio 1, notebook 1, notebook-shim 1, overrides 1,
packaging 1, pandocfilters 1, parso 1, pexpect 1, platformdirs 1,
prometheus-client 1, prompt-toolkit 1, psutil 1, ptyprocess 1, pure-eval
1, pycparser 1, pygments 1, python-dateutil 1, python-json-logger 1,
pyyaml 1, pyzmq 1, qtconsole 1, qtpy 1, referencing 1, requests 1,
rfc3339-validator 1, rfc3986-validator 1, root 1, rpds-py 1, send2trash
1, six 1, sniffio 1, soupsieve 1, stack-data 1, terminado 1, tinycss2 1,
tomli 1, tornado 1, traitlets 1, types-python-dateutil 1,
typing-extensions 1, uri-template 1, urllib3 1, wcwidth 1, webcolors 1,
webencodings 1, websocket-client 1, widgetsnbextension 1
* boto3: botocore 1697, boto3 849, urllib3 2, jmespath 1,
python-dateutil 1, root 1, s3transfer 1, six 1
* transformers-extras: Tried 1191 versions: sagemaker 152, hypothesis
67, tensorflow 21, jsonschema 19, tensorflow-cpu 18, multiprocess 10,
pathos 10, tensorflow-text 10, chex 8, tf-keras 8, tf2onnx 8, aiohttp 6,
aiosignal 6, alembic 6, annotated-types 6, apscheduler 6, attrs 6,
backoff 6, binaryornot 6, black 6, boto3 6, click 6, coloredlogs 6,
colorlog 6, dash 6, dash-bootstrap-components 6, dlinfo 6,
exceptiongroup 6, execnet 6, fire 6, frozenlist 6, gitdb 6, google-auth
6, google-auth-oauthlib 6, hjson 6, iniconfig 6, jinja2-time 6, markdown
6, markdown-it-py 6, markupsafe 6, mpmath 6, namex 6, nbformat 6, ninja
6, nvidia-nvjitlink-cu12 6, onnxconverter-common 6, pandas 6, plac 6,
platformdirs 6, pluggy 6, portalocker 6, poyo 6, protobuf3-to-dict 6,
py-cpuinfo 6, py3nvml 6, pyarrow 6, pyarrow-hotfix 6, pydantic-core 6,
pygments 6, pynvml 6, pypng 6, python-slugify 6, responses 6,
smdebug-rulesconfig 6, soupsieve 6, sqlalchemy 6,
tensorboard-data-server 6, tensorboard-plugin-wit 6, tensorboardx 6,
threadpoolctl 6, tomli 6, wasabi 6, wcwidth 6, werkzeug 6, wheel 6,
xxhash 6, zipp 6, etils 5, tensorboard 5, beautifulsoup4 4, cffi 4,
clldutils 4, codecarbon 4, datasets 4, dill 4, evaluate 4, gitpython 4,
hf-doc-builder 4, kenlm 4, librosa 4, llvmlite 4, nest-asyncio 4, nltk
4, optuna 4, parameterized 4, phonemizer 4, psutil 4, pyctcdecode 4,
pytest 4, pytest-timeout 4, pytest-xdist 4, ray 4, rjieba 4, rouge-score
4, ruff 4, sacrebleu 4, sacremoses 4, sigopt 4, sortedcontainers 4,
tensorstore 4, timeout-decorator 4, toolz 4, torchaudio 4, accelerate 3,
audioread 3, cookiecutter 3, decorator 3, deepspeed 3, faiss-cpu 3, flax
3, fugashi 3, ipadic 3, isort 3, jax 3, jaxlib 3, joblib 3, keras-nlp 3,
lazy-loader 3, numba 3, optax 3, pooch 3, pydantic 3, pygtrie 3, rhoknp
3, scikit-learn 3, segments 3, soundfile 3, soxr 3, sudachidict-core 3,
sudachipy 3, torch 3, unidic 3, unidic-lite 3, urllib3 3, absl-py 2,
arrow 2, astunparse 2, async-timeout 2, botocore 2, cachetools 2,
certifi 2, chardet 2, charset-normalizer 2, csvw 2, dash-core-components
2, dash-html-components 2, dash-table 2, diffusers 2, dm-tree 2,
fastjsonschema 2, flask 2, flatbuffers 2, fsspec 2, ftfy 2, gast 2,
google-pasta 2, greenlet 2, grpcio 2, h5py 2, humanfriendly 2, idna 2,
importlib-metadata 2, importlib-resources 2, jinja2 2, jmespath 2,
jupyter-core 2, kagglehub 2, keras 2, keras-core 2, keras-preprocessing
2, libclang 2, mako 2, mdurl 2, ml-dtypes 2, msgpack 2, multidict 2,
mypy-extensions 2, networkx 2, nvidia-cublas-cu12 2,
nvidia-cuda-cupti-cu12 2, nvidia-cuda-nvrtc-cu12 2,
nvidia-cuda-runtime-cu12 2, nvidia-cudnn-cu12 2, nvidia-cufft-cu12 2,
nvidia-curand-cu12 2, nvidia-cusolver-cu12 2, nvidia-cusparse-cu12 2,
nvidia-nccl-cu12 2, nvidia-nvtx-cu12 2, onnx 2, onnxruntime 2,
onnxruntime-tools 2, opencv-python 2, opt-einsum 2, orbax-checkpoint 2,
pathspec 2, plotly 2, pox 2, ppft 2, pyasn1-modules 2, pycparser 2,
pyrsistent 2, python-dateutil 2, pytz 2, requests-oauthlib 2, retrying
2, rich 2, rsa 2, s3transfer 2, scipy 2, setuptools 2, six 2, smmap 2,
sympy 2, tabulate 2, tensorflow-estimator 2, tensorflow-hub 2,
tensorflow-io-gcs-filesystem 2, termcolor 2, text-unidecode 2, traitlets
2, triton 2, typing-extensions 2, tzdata 2, tzlocal 2, wrapt 2,
xmltodict 2, yarl 2, Python 1, av 1, babel 1, bibtexparser 1, blinker 1,
colorama 1, decord 1, filelock 1, huggingface-hub 1, isodate 1,
itsdangerous 1, language-tags 1, lxml 1, numpy 1, oauthlib 1, packaging
1, pillow 1, protobuf 1, pyasn1 1, pylatexenc 1, pyparsing 1, pyyaml 1,
rdflib 1, regex 1, requests 1, rfc3986 1, root 1, safetensors 1,
sentencepiece 1, tenacity 1, timm 1, tokenizers 1, torchvision 1, tqdm
1, transformers 1, types-python-dateutil 1, uritemplate 1


You can reproduce them with python 3.10 and:
```
RUST_LOG=uv_resolver=debug cargo run pip compile -o /dev/null -q scripts/requirements/<input>.in 2>&1 | tail -n 1
```

Closes #2270 - This is less invasive compared to the other PR, we can
revisit number of network/build request tracking later.
2024-04-17 09:08:21 +00:00
Charlie Marsh b3f98d5e05
Use kebab-case for serde enums (#3080)
By default, these serialize as (e.g.) `LowestDirect`. This now matches
the format we use in Ruff.
2024-04-17 01:13:39 +00:00
Charlie Marsh 295b58ad37
Add `uv-workspace` crate with settings discovery and deserialization (#3007)
## Summary

This PR adds basic struct definitions along with a "workspace" concept
for discovering settings. (The "workspace" terminology is used to match
Ruff; I did not invent it.)

A few notes:

- We discover any `pyproject.toml` or `uv.toml` file in any parent
directory of the current working directory. (We could adjust this to
look at the directories of the input files.)
- We don't actually do anything with the configuration yet; but those
PRs are large and I want this to be reviewed in isolation.
2024-04-16 13:56:47 -04:00
konsti 88d6a55dbf
Show package name in no version for direct dependency error (#3056)
Fixes #3053
2024-04-16 07:57:13 +00:00
Charlie Marsh 1f626bfc73
Move `ExcludeNewer` into its own type (#3041)
## Summary

This makes it easier to add (e.g.) JSON Schema derivations to the type.

If we have support for other dates in the future, we can generalize it
to a `UserDate` or similar.
2024-04-15 20:24:08 +00:00
konsti 7f70849e3c
Support freethreading python (#2805)
freethreaded python reintroduces abiflags since it is incompatible with
regular native modules and abi3.

Tests: None yet! We're lacking cpython 3.13 no-gil builds we can use in
ci.

My test setup:

```
PYTHON_CONFIGURE_OPTS="--enable-shared --disable-gil" pyenv install 3.13.0a5
cargo run -q -- venv -q -p python3.13 .venv3.13 --no-cache-dir && cargo run -q -- pip install -v psutil --no-cache-dir && .venv3.13/bin/python -c "import psutil"
```

Fixes #2429
2024-04-12 09:39:47 +00:00
Charlie Marsh 96c3c2e774
Support unnamed requirements in `--require-hashes` (#2993)
## Summary

This PR enables `--require-hashes` with unnamed requirements. The key
change is that `PackageId` becomes `VersionId` (since it refers to a
package at a specific version), and the new `PackageId` consists of
_either_ a package name _or_ a URL. The hashes are keyed by `PackageId`,
so we can generate the `RequiredHashes` before we have names for all
packages, and enforce them throughout.

Closes #2979.
2024-04-11 11:26:50 -04:00
Charlie Marsh 006379c50c
Add support for URL requirements in `--generate-hashes` (#2952)
## Summary

This PR enables hash generation for URL requirements when the user
provides `--generate-hashes` to `pip compile`. While we include the
hashes from the registry already, today, we omit hashes for URLs.

To power hash generation, we introduce a `HashPolicy` abstraction:

```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HashPolicy<'a> {
    /// No hash policy is specified.
    None,
    /// Hashes should be generated (specifically, a SHA-256 hash), but not validated.
    Generate,
    /// Hashes should be validated against a pre-defined list of hashes. If necessary, hashes should
    /// be generated so as to ensure that the archive is valid.
    Validate(&'a [HashDigest]),
}
```

All of the methods on the distribution database now accept this policy,
instead of accepting `&'a [HashDigest]`.

Closes #2378.
2024-04-10 20:02:45 +00:00
Charlie Marsh 8513d603b4
Return computed hashes from metadata requests (#2951)
## Summary

This PR modifies the distribution database to return both the
`Metadata23` and the computed hashes when clients request metadata.

No behavior changes, but this will be necessary to power
`--generate-hashes`.
2024-04-10 19:31:41 +00:00
Charlie Marsh c18551fd3c
Fall back to distributions without hashes in resolver (#2949)
## Summary

This represents a change to `--require-hashes` in the event that we
don't find a matching hash from the registry. The behavior in this PR is
closer to pip's.

Prior to this PR, if a distribution had no reported hash, or only
mismatched hashes, we would mark it as incompatible. Now, we mark it as
compatible, but we use the hash-agreement as part of the ordering, such
that we prefer any distribution with a matching hash, then any
distribution with no hash, then any distribution with a mismatched hash.

As a result, if an index reports incorrect hashes, but the user provides
the correct one, resolution now succeeds, where it would've failed.

Similarly, if an index omits hashes altogether, but the user provides
the correct one, resolution now succeeds, where it would've failed.

If we end up picking a distribution whose hash ultimately doesn't match,
we'll reject it later, after resolution.
2024-04-10 19:19:47 +00:00
Charlie Marsh 1f3b5bb093
Add hash-checking support to `install` and `sync` (#2945)
## Summary

This PR adds support for hash-checking mode in `pip install` and `pip
sync`. It's a large change, both in terms of the size of the diff and
the modifications in behavior, but it's also one that's hard to merge in
pieces (at least, with any test coverage) since it needs to work
end-to-end to be useful and testable.

Here are some of the most important highlights:

- We store hashes in the cache. Where we previously stored pointers to
unzipped wheels in the `archives` directory, we now store pointers with
a set of known hashes. So every pointer to an unzipped wheel also
includes its known hashes.
- By default, we don't compute any hashes. If the user runs with
`--require-hashes`, and the cache doesn't contain those hashes, we
invalidate the cache, redownload the wheel, and compute the hashes as we
go. For users that don't run with `--require-hashes`, there will be no
change in performance. For users that _do_, the only change will be if
they don't run with `--generate-hashes` -- then they may see some
repeated work between resolution and installation, if they use `pip
compile` then `pip sync`.
- Many of the distribution types now include a `hashes` field, like
`CachedDist` and `LocalWheel`.
- Our behavior is similar to pip, in that we enforce hashes when pulling
any remote distributions, and when pulling from our own cache. Like pip,
though, we _don't_ enforce hashes if a distribution is _already_
installed.
- Hash validity is enforced in a few different places:
1. During resolution, we enforce hash validity based on the hashes
reported by the registry. If we need to access a source distribution,
though, we then enforce hash validity at that point too, prior to
running any untrusted code. (This is enforced in the distribution
database.)
2. In the install plan, we _only_ add cached distributions that have
matching hashes. If a cached distribution is missing any hashes, or the
hashes don't match, we don't return them from the install plan.
3. In the downloader, we _only_ return distributions with matching
hashes.
4. The final combination of "things we install" are: (1) the wheels from
the cache, and (2) the downloaded wheels. So this ensures that we never
install any mismatching distributions.
- Like pip, if `--require-hashes` is provided, we require that _all_
distributions are pinned with either `==` or a direct URL. We also
require that _all_ distributions have hashes.

There are a few notable TODOs:

- We don't support hash-checking mode for unnamed requirements. These
should be _somewhat_ rare, though? Since `pip compile` never outputs
unnamed requirements. I can fix this, it's just some additional work.
- We don't automatically enable `--require-hashes` with a hash exists in
the requirements file. We require `--require-hashes`.

Closes #474.

## Test Plan

I'd like to add some tests for registries that report incorrect hashes,
but otherwise: `cargo test`
2024-04-10 19:09:03 +00:00
Charlie Marsh 48ba7df98a
Move `FlatIndex` into the `uv-resolver` crate (#2972)
## Summary

This lets us remove circular dependencies (in the future, e.g., #2945)
that arise from `FlatIndex` needing a bunch of resolver-specific
abstractions (like incompatibilities, required hashes, etc.) that aren't
necessary to _fetch_ the flat index entries.
2024-04-10 14:38:42 -04:00
Charlie Marsh a9d554fa90
Add a `--require-hashes` command-line setting (#2824)
## Summary

I'll likely only merge this once the PR chain is further along, but this
PR wires up the setting fro the CLI.
2024-04-10 14:07:03 -04:00
Chan Kang 7cd98d2499
Implement `--emit-index-annotation` to annotate source index for each package (#2926)
## Summary
resolves https://github.com/astral-sh/uv/issues/2852

## Test Plan
add a couple of tests:
- one covering the simplest case with all packages pulled from a single
index.
- another where packages are pull from two distinct indices.

tested manually as well:
```
$ (echo 'pandas'; echo 'torch') | UV_EXTRA_INDEX_URL='https://download.pytorch.org/whl/cpu' cargo run pip compile - --include-indices 
    Finished dev [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/uv pip compile - --include-indices`
Resolved 15 packages in 686ms
# This file was autogenerated by uv via the following command:
#    uv pip compile - --include-indices
filelock==3.9.0
    # via torch
    # from https://download.pytorch.org/whl/cpu
fsspec==2023.4.0
    # via torch
    # from https://download.pytorch.org/whl/cpu
jinja2==3.1.2
    # via torch
    # from https://download.pytorch.org/whl/cpu
markupsafe==2.1.3
    # via jinja2
    # from https://download.pytorch.org/whl/cpu
mpmath==1.3.0
    # via sympy
    # from https://download.pytorch.org/whl/cpu
networkx==3.2.1
    # via torch
    # from https://download.pytorch.org/whl/cpu
numpy==1.26.3
    # via pandas
    # from https://download.pytorch.org/whl/cpu
pandas==2.2.1
    # from https://pypi.org/simple
python-dateutil==2.9.0.post0
    # via pandas
    # from https://pypi.org/simple
pytz==2024.1
    # via pandas
    # from https://pypi.org/simple
six==1.16.0
    # via python-dateutil
    # from https://pypi.org/simple
sympy==1.12
    # via torch
    # from https://download.pytorch.org/whl/cpu
torch==2.2.2
    # from https://download.pytorch.org/whl/cpu
typing-extensions==4.8.0
    # via torch
    # from https://download.pytorch.org/whl/cpu
tzdata==2024.1
    # via pandas
    # from https://pypi.org/simple
```
2024-04-10 16:05:58 +00:00
Charlie Marsh d8323551f8
Update hashes without `--upgrade` if not present (#2966)
## Summary

If the user runs with `--generate-hashes`, and the lockfile doesn't
contain _any_ hashes for a package (despite being pinned), we should add
new hashes. This mirrors running `uv pip compile --generate-hashes` for
the first time with an existing lockfile.

Closes #2962.
2024-04-10 14:56:34 +00:00
Charlie Marsh c4472ebbb9
Enforce and backtrack on invalid versions in source metadata (#2954)
## Summary

If we build a source distribution from the registry, and the version
doesn't match that of the filename, we should error, just as we do for
mismatched package names. However, we should also backtrack here, which
we didn't previously.

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

## Test Plan

Verified that `cargo run pip install docutils --verbose --no-cache
--reinstall` installs `docutils==0.21` instead of the invalid
`docutils==0.21.post1`.

In the logs, I see:

```
WARN Unable to extract metadata for docutils: Package metadata version `0.21` does not match given version `0.21.post1`
```
2024-04-10 05:13:33 +00:00
Charlie Marsh 7ae06b3b46
Surface invalid metadata as hints in error reports (#2850)
## Summary

Closes #2847.
2024-04-09 23:12:10 -04:00
Charlie Marsh f9c0632953
Ignore direct URL distributions in prefetcher (#2943)
## Summary

The prefetcher tallies the number of times we tried a given package, and
then once we hit a threshold, grabs the version map, assuming it's
already been fetched. For direct URL distributions, though, we don't
have a version map! And there's no need to prefetch.

Closes https://github.com/astral-sh/uv/issues/2941.
2024-04-09 14:09:41 -05:00
Charlie Marsh 13ae5ac8dc
Replace PyPI-internal Hashes representation with flat vector (#2925)
## Summary

Right now, we have a `Hashes` representation that looks like:

```rust
/// A dictionary mapping a hash name to a hex encoded digest of the file.
///
/// PEP 691 says multiple hashes can be included and the interpretation is left to the client.
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize)]
pub struct Hashes {
    pub md5: Option<Box<str>>,
    pub sha256: Option<Box<str>>,
    pub sha384: Option<Box<str>>,
    pub sha512: Option<Box<str>>,
}
```

It stems from the PyPI API, which returns a dictionary of hashes.

We tend to pass these around as a vector of `Vec<Hashes>`. But it's a
bit strange because each entry in that vector could contain multiple
hashes. And it makes it difficult to ask questions like "Is
`sha256:ab21378ca980a8` in the set of hashes"?

This PR instead treats `Hashes` as the PyPI-internal type, and uses a
new `Vec<HashDigest>` everywhere in our own APIs.
2024-04-09 16:56:16 +00:00
Zanie Blue 1512e07a2e
Split configuration options out of `uv-types` (#2924)
Needed to prevent circular dependencies in my toolchain work (#2931). I
think this is probably a reasonable change as we move towards persistent
configuration too?

Unfortunately `BuildIsolation` needs to be in `uv-types` to avoid
circular dependencies still. We might be able to resolve that in the
future.
2024-04-09 11:35:53 -05:00
konsti fb4ba2bbc2
Speed up cold cache urllib3/boto3/botocore with batched prefetching (#2452)
With pubgrub being fast for complex ranges, we can now compute the next
n candidates without taking a performance hit. This speeds up cold cache
`urllib3<1.25.4` `boto3` from maybe 40s - 50s to ~2s. See docstrings for
details on the heuristics.

**Before**


![image](https://github.com/astral-sh/uv/assets/6826232/b7b06950-e45b-4c49-b65e-ae19fe9888cc)

**After**


![image](https://github.com/astral-sh/uv/assets/6826232/1c749248-850e-49c1-9d57-a7d78f87b3aa)

---

We need two parts of the prefetching, first looking for compatible
version and then falling back to flat next versions. After we selected a
boto3 version, there is only one compatible botocore version remaining,
so when won't find other compatible candidates for prefetching. We see
this as a pattern where we only prefetch boto3 (stack bars), but not
botocore (sequential requests between the stacked bars).


![image](https://github.com/astral-sh/uv/assets/6826232/e5186800-23ac-4ed1-99b9-4d1046fbd03a)

The risk is that we're completely wrong with the guess and cause a lot
of useless network requests. I think this is acceptable since this
mechanism only triggers when we're already on the bad path and we should
simply have fetched all versions after some seconds (assuming a fast
index like pypi).

---

It would be even better if the pubgrub state was copy-on-write so we
could simulate more progress than we actually have; currently we're
guessing what the next version is which could be completely wrong, but i
think this is still a valuable heuristic.

Fixes #170.
2024-04-08 14:28:56 +00:00
Charlie Marsh 35940cb885
Remove additional 'because' (#2849)
## Summary

Is this, perhaps, not totally necessary? It doesn't show up in any
fixtures beyond those that I added recently.

Closes https://github.com/astral-sh/uv/issues/2846.
2024-04-06 10:58:23 -04:00
Charlie Marsh 00934044aa
Backtrack on distributions with invalid metadata (#2834)
## Summary

Closes https://github.com/astral-sh/uv/issues/2821.
2024-04-05 18:00:48 -04:00
konsti 5474c61fed
Refactor candidate selector for batch prefetching (#2832)
Batch prefetching needs more information from the candidate selector, so
i've split `select` into methods. Split out from #2452. No functional
changes.
2024-04-05 16:51:01 +02:00
Charlie Marsh 34341bd6e9
Allow package lookups across multiple indexes via explicit opt-in (#2815)
## Summary

This partially revives https://github.com/astral-sh/uv/pull/2135 (with
some modifications) to enable users to opt-in to looking for packages
across multiple indexes.

The behavior is such that, in version selection, we take _any_
compatible version from a "higher-priority" index over the compatible
versions of a "lower-priority" index, even if that means we might accept
an "older" version.

Closes https://github.com/astral-sh/uv/issues/2775.
2024-04-03 23:23:37 +00:00
Charlie Marsh 189d0d41d0
Remove redirects from the resolver (#2792)
## Summary

Rather than storing the `redirects` on the resolver, this PR just
re-uses the "convert this URL to precise" logic when we convert to a
`Resolution` after-the-fact. I think this is a lot simpler: it removes
state from the resolver, and simplifies a lot of the hooks around
distribution fetching (e.g., `get_or_build_wheel_metadata` no longer
returns `(Metadata23, Option<Url>)`).
2024-04-03 02:43:57 +00:00
Charlie Marsh c30a65ee0c
Allow conflicting Git URLs that refer to the same commit SHA (#2769)
## Summary

This PR leverages our lookahead direct URL resolution to significantly
improve the range of Git URLs that we can accept (e.g., if a user
provides the same requirement, once as a direct dependency, and once as
a tag). We did some of this in #2285, but the solution here is more
general and works for arbitrary transitive URLs.

Closes https://github.com/astral-sh/uv/issues/2614.
2024-04-02 23:36:35 +00:00
Zanie Blue 1ac9672b95
Resolve non-determistic behavior in preferences due to site-packages ordering (#2780)
Originally a regression test for #2779 but we found out that there's
some weird behavior where different `anyio` versions were preferred
based on the platform.
2024-04-02 13:48:33 -05:00
Zanie Blue 119d753cfe
Exclude installed distributions with multiple versions from consideration in the resolver (#2779)
Addresses panic introduced in #2596 and reported in
https://github.com/astral-sh/uv/issues/2763#issuecomment-2030674936

When there are multiple versions of a package available, we remove the
existing packages before installing the resolved version to "fix" the
environment. We must remove all of the package versions and reinstall
because removing _any_ of the package versions could break the others.
Since reinstalls require a pull from the remote, this broke a contract
between the resolver and the planner which must always agree on which
packages should come from the remote. This further demonstrates that we
should be constructing the install plan with more concrete knowledge
from the resolver (i.e. `ResolvedDist` instead of `Requirement`) to
avoid having to manually ensure logic matches.

## Test plan

Fails on `main` with panic succeeds on branch

```
uv venv --seed
source .venv/bin/activate
pip install anyio==3.7.0 --ignore-installed
pip install anyio==4.0.0 --ignore-installed
cargo run -- pip install anyio black -v
```
2024-04-02 12:10:52 -05:00
Charlie Marsh f2c9e88f3e
Populate the in-memory index when resolving lookahead URLs (#2761)
## Summary

Just ensures that we don't have to go back to the cache when resolving.
2024-04-01 22:07:54 +00:00
Charlie Marsh 999d653404
Use canonical URL to key redirect map (#2764)
## Summary

This fixes a potential bug that revealed itself in
https://github.com/astral-sh/uv/pull/2761. We don't run into this now
because we always use "allowed URLs", stores the "last" compatible URL
in the map. But the use of the "raw" URL (rather than the "canonical"
URL) means that other writers have to follow that same assumption and
iterate over dependencies in-order.
2024-04-01 17:57:13 -04:00
Charlie Marsh a48bcaecb1
Recursively resolve direct URL references upfront (#2684)
## Summary

This PR would enable us to support transitive URL requirements. The key
idea is to leverage the fact that...

- URL requirements can only come from URL requirements.
- URL requirements identify a _specific_ version, and so don't require
backtracking.

Prior to running the "real" resolver, we recursively resolve any URL
requirements, and collect all the known URLs upfront, then pass those to
the resolver as "lookahead" requirements. This means the resolver knows
upfront that if a given package is included, it _must_ use the provided
URL.

Closes https://github.com/astral-sh/uv/issues/1808.
2024-04-01 21:16:20 +00:00
Charlie Marsh 8596ff3470
Remove `Cache` argument from `DistributionDatabase` (#2749)
## Summary

We can access cache from `BuildContext`. This mirrors
`SourceDistCachedBuilder`, which doesn't accept `Cache` as an argument
and always accesses it through `BuildContext`.
2024-03-31 22:22:25 -04:00
Charlie Marsh c669542a9e
Respect overrides in all direct-dependency iterators (#2742)
## Summary

We iterate over the project "requirements" directly in a variety of
places. However, it's not always the case that an input "requirement" on
its own will _actually_ be part of the resolution, since we support
"overrides".

Historically, then, overrides haven't worked as expected for _direct_
dependencies (and we have some tests that demonstrate the current,
"wrong" behavior). This is just a bug, but it's not really one that
comes up in practice, since it's rare to apply an override to your _own_
dependency.

However, we're now considering expanding the lookahead concept to
include local transitive dependencies. In this case, it's more and more
important that overrides and constraints are handled consistently.

This PR modifies all the locations in which we iterate over requirements
directly, and modifies them to respect overrides (and constraints, where
necessary).
2024-03-31 14:03:49 -04:00
Charlie Marsh 6d5b5ae9a2
Use distinct `Constraints` and `Overrides` types more widely (#2741)
## Summary

No functional changes.
2024-03-31 13:46:37 -04:00
Zanie Blue e1878c8359
Consider installed packages during resolution (#2596)
Previously, we did not consider installed distributions as candidates
while performing resolution. Here, we update the resolver to use
installed distributions that satisfy requirements instead of pulling new
distributions from the registry.

The implementation details are as follows:

- We now provide `SitePackages` to the `CandidateSelector`
- If an installed distribution satisfies the requirement, we prefer it
over remote distributions
- We do not want to allow installed distributions in some cases, i.e.,
upgrade and reinstall
- We address this by introducing an `Exclusions` type which tracks
installed packages to ignore during selection
- There's a new `ResolvedDist` wrapper with `Installed(InstalledDist)`
and `Installable(Dist)` variants
- This lets us pass already installed distributions throughout the
resolver

The user-facing behavior is thoroughly covered in the tests, but
briefly:

- Installing a package that depends on an already-installed package
prefers the local version over the index
- Installing a package with a name that matches an already-installed URL
package does not reinstall from the index
- Reinstalling (--reinstall) a package by name _will_ pull from the
index even if an already-installed URL package is present
- To reinstall the URL package, you must specify the URL in the request

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

Addresses:

- https://github.com/astral-sh/uv/issues/1476
- https://github.com/astral-sh/uv/issues/1856
- https://github.com/astral-sh/uv/issues/2093
- https://github.com/astral-sh/uv/issues/2282
- https://github.com/astral-sh/uv/issues/2383
- https://github.com/astral-sh/uv/issues/2560

## Test plan

- [x] Reproduction at `charlesnicholson/uv-pep420-bug` passes
- [x] Unit test for editable package
([#1476](https://github.com/astral-sh/uv/issues/1476))
- [x] Unit test for previously installed package with empty registry
- [x] Unit test for local non-editable package
- [x] Unit test for new version available locally but not in registry
([#2093](https://github.com/astral-sh/uv/issues/2093))
- ~[ ] Unit test for wheel not available in registry but already
installed locally
([#2282](https://github.com/astral-sh/uv/issues/2282))~ (seems
complicated and not worthwhile)
- [x] Unit test for install from URL dependency then with matching
version ([#2383](https://github.com/astral-sh/uv/issues/2383))
- [x] Unit test for install of new package that depends on installed
package does not change version
([#2560](https://github.com/astral-sh/uv/issues/2560))
- [x] Unit test that `pip compile` does _not_ consider installed
packages
2024-03-28 13:49:17 -05:00
Charlie Marsh 4cc91cc6bb
Add convenience methods to `Manifest` to iterate over requirements (#2701)
## Summary

These are repeated a bunch. It's nice to DRY them up and ensure the
ordering is consistent.
2024-03-28 01:03:44 +00:00
Charlie Marsh b6ab919945
Make tags non-required for fetching wheel metadata (#2700)
## Summary

This looks like a big change but it really isn't. Rather, I just split
`get_or_build_wheel` into separate `get_wheel` and `build_wheel` methods
internally, which made `get_or_build_wheel_metadata` capable of _not_
relying on `Tags`, which in turn makes it easier for us to use the
`DistributionDatabase` in various places without having it coupled to an
interpreter or environment (something we already did for
`SourceDistributionBuilder`).
2024-03-28 00:06:25 +00:00
Charlie Marsh cf30932831
Allow prereleases, locals, and URLs in non-editable path requirements (#2671)
## Summary

This PR enables the resolver to "accept" URLs, prereleases, and local
version specifiers for direct dependencies of path dependencies. As a
result, `uv pip install .` and `uv pip install -e .` now behave
identically, in that neither has a restriction on URL dependencies and
the like.

Closes https://github.com/astral-sh/uv/issues/2643.
Closes https://github.com/astral-sh/uv/issues/1853.
2024-03-27 22:17:09 +00:00
Charlie Marsh f8fa887c0b
Use `Resolver` in `pip sync` (#2696)
## Summary

This PR removes the custom `DistFinder` that we use in `pip sync`. This
originally existed because `VersionMap` wasn't lazy, and so we saved a
lot of time in `DistFinder` by reading distribution data lazily. But
now, AFAICT, there's really no benefit. Maintaining `DistFinder` means
we effectively have to maintain two resolvers, and end up fixing bugs in
`DistFinder` that don't exist in the `Resolver` (like #2688.

Closes #2694.

Closes #2443.

## Test Plan

I ran this benchmark a bunch. It's basically a wash. Sometimes one is
faster than the other.

```
❯ python -m scripts.bench \
        --uv-path ./target/release/main \
        --uv-path ./target/release/uv \
        scripts/requirements/compiled/trio.txt --min-runs 50 --benchmark install-warm --warmup 25
Benchmark 1: ./target/release/main (install-warm)
  Time (mean ± σ):      54.0 ms ±  10.6 ms    [User: 8.7 ms, System: 98.1 ms]
  Range (min … max):    45.5 ms …  94.3 ms    50 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet PC without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: ./target/release/uv (install-warm)
  Time (mean ± σ):      50.7 ms ±   9.2 ms    [User: 8.7 ms, System: 98.6 ms]
  Range (min … max):    44.0 ms …  98.6 ms    50 runs

  Warning: The first benchmarking run for this command was significantly slower than the rest (77.6 ms). 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.

Summary
  './target/release/uv (install-warm)' ran
    1.06 ± 0.29 times faster than './target/release/main (install-warm)'
```
2024-03-27 17:36:38 -04:00
Charlie Marsh dc957d7322
Respect `--no-index` with `--find-links` in `pip sync` (#2692)
## Summary

In `pip sync`, we weren't properly handling cases in which a package
_only_ existed in `--find-links` (e.g., the user passed `--offline` or
`--no-index`).

I plan to explore removing `Finder` entirely to avoid these mismatch
bugs between `pip sync` and other commands, but this is fine for now.

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

## Test Plan

`cargo test`
2024-03-27 16:15:14 +00:00
Andrew Gallant 980dcc3324 uv-resolver: add new 'marker_tree' method on ResolutionGraph
This routine generates a marker expression that, when evaluated
to true, implies that the resolution graph is guaranteed to be
valid.
2024-03-27 11:22:29 -04:00
Andrew Gallant 50e48847f1 uv-resolver: add Clone impls
For $reasons, we'll want to be able to clone a `Manifest` so
that it can be re-used to generate a marker expression.

There is likely a refactoring that could be done to avoid the
cloning, but a `Manifest` is likely to be small in practice, and
we'll only need to clone it once.
2024-03-27 11:22:29 -04:00
Charlie Marsh 8c7a6038fd
Update Rust to v1.77 (#2591) 2024-03-27 14:41:27 +00:00
Zanie Blue 0b08ba1e67
Rename `uv-traits` and split into separate modules (#2674)
This is driving me a little crazy and is becoming a larger problem in
#2596 where I need to move more types (like `Upgrade` and `Reinstall`)
into this crate. Anything that's shared across our core resolver,
install, and build crates needs to be defined in this crate to avoid
cyclic dependencies. We've outgrown it being a single file with some
shared traits.

There are no behavioral changes here.
2024-03-26 15:39:43 -05:00
konsti 33bde826a0
Update pubgrub to use a dependency provider (#2648)
With https://github.com/pubgrub-rs/pubgrub/pull/190, pubgrub attaches
all types to a dependency provider to reduce the number of generics. We
need a dummy dependency provider now to emulate this. On the plus side,
pep440_rs drops its pubgrub dependency.
2024-03-25 15:51:31 +01:00
Charlie Marsh 90a1f89ac4
Extract local versions from direct URL requirements (#2624)
## Summary

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

## Test Plan

`cargo run pip install -r requirements.txt`, with:

```
 whisperX @ befe2b242e.zip
 pyannote-audio @ git+https://github.com/pyannote/pyannote-audio@11b56a137a578db9335efc00298f6ec1932e6317
 torch @ https://download.pytorch.org/whl/cu118/torch-2.2.1%2Bcu118-cp311-cp311-linux_x86_64.whl#sha256=84328a35621cc6a67a182a327baaab67e5f5869981c4b1677ed05f92c15cceb1
 torchaudio @ https://download.pytorch.org/whl/cu118/torchaudio-2.2.1%2Bcu118-cp311-cp311-linux_x86_64.whl#sha256=cd3b1c3582b17792c6d7a367dea0459b123e54d7a4242809ea87ccc10fa220e5
 pytorch_triton @ https://download.pytorch.org/whl/nightly/pytorch_triton-2.1.0%2B7d1a95b046-cp311-cp311-linux_x86_64.whl
```
2024-03-22 21:34:14 +00:00
Wolf Vollprecht 68432e77e5
fix: expose `AllowedYanks` (#2608)
## Summary

If I see correctly, this is used in the interface of
`DefaultResolverProvider` but not accessible outside.
2024-03-22 09:15:22 -05:00
konsti 48bd02b8a8
Update miette v7, pubgrub and small Cargo.toml cleanup (#2610)
I was going through the output of `cargo tree --duplicate -p uv`, not
much success except these small cleanups.
2024-03-22 10:42:48 +00:00
Charlie Marsh 0ea51d43f5
Add progress reporting for named requirement resolution (#2605) 2024-03-22 04:01:10 +00:00
Charlie Marsh 31743f2bd8
Use PEP 517 build hooks to resolve unnamed requirements (#2604) 2024-03-22 03:20:40 +00:00
Charlie Marsh 5d7d7dce24
Enable PEP 517 builds for unnamed requirements (#2600)
## Summary

This PR enables the source distribution database to be used with unnamed
requirements (i.e., URLs without a package name). The (significant)
upside here is that we can now use PEP 517 hooks to resolve unnamed
requirement metadata _and_ reuse any computation in the cache.

The changes to `crates/uv-distribution/src/source/mod.rs` are quite
extensive, but mostly mechanical. The core idea is that we introduce a
new `BuildableSource` abstraction, which can either be a distribution,
or an unnamed URL:

```rust
/// A reference to a source that can be built into a built distribution.
///
/// This can either be a distribution (e.g., a package on a registry) or a direct URL.
///
/// Distributions can _also_ point to URLs in lieu of a registry; however, the primary distinction
/// here is that a distribution will always include a package name, while a URL will not.
#[derive(Debug, Clone, Copy)]
pub enum BuildableSource<'a> {
    Dist(&'a SourceDist),
    Url(SourceUrl<'a>),
}
```

All the methods on the source distribution database now accept
`BuildableSource`. `BuildableSource` has a `name()` method, but it
returns `Option<&PackageName>`, and everything is required to work with
and without a package name.

The main drawback of this approach (which isn't a terrible one) is that
we can no longer include the package name in the cache. (We do continue
to use the package name for registry-based distributions, since those
always have a name.). The package name was included in the cache route
for two reasons: (1) it's nice for debugging; and (2) we use it to power
`uv cache clean flask`, to identify the entries that are relevant for
Flask.

To solve this, I changed the `uv cache clean` code to look one level
deeper. So, when we want to determine whether to remove the cache entry
for a given URL, we now look into the directory to see if there are any
wheels that match the package name. This isn't as nice, but it does work
(and we have test coverage for it -- all passing).

I also considered removing the package name from the cache routes for
non-registry _wheels_, for consistency... But, it would require a cache
bump, and it didn't feel important enough to merit that.
2024-03-21 22:46:39 -04:00
Charlie Marsh ee211b35bc
Add support for parsing unnamed URL requirements (#2567)
## Summary

First piece of https://github.com/astral-sh/uv/issues/313. In order to
support unnamed requirements, we need to be able to parse them in
`requirements-txt`, which in turn means that we need to introduce a new
type that's distinct from `pep508::Requirement`, given that these
_aren't_ PEP 508-compatible requirements.

Part of: https://github.com/astral-sh/uv/issues/313.
2024-03-21 03:28:58 +00:00
konsti 70e0967dbd
Avoid repeating paths of workspace packages (#2573)
Scott schafer got me the idea: We can avoid repeating the path for
workspaces dependencies everywhere if we declare them in the virtual
package once and treat them as workspace dependencies from there on.
2024-03-20 16:16:02 -04:00