Commit graph

763 commits

Author SHA1 Message Date
Charlie Marsh
7d1b7b99d9
Rename Dependency.id to Dependency.distribution_id (#4114)
## Summary

I think this makes clearer that the `Dependency.id` is not an identifier
for the dependency itself.

No functional changes.
2024-06-07 18:28:54 +00:00
Charlie Marsh
fa10679275
Add extra and dev dependency validation to lockfile (#4112)
## Summary

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

Closes https://github.com/astral-sh/uv/issues/4115.
2024-06-07 14:18:31 -04:00
Charlie Marsh
cc7c780523
Remove PubGrub dependency from uv (#4116)
## Summary

Encapsulates more of the details are `Requires-Python` and PubGrub.

Closes https://github.com/astral-sh/uv/issues/4110.
2024-06-06 23:45:58 +00:00
Charlie Marsh
677a7f157b
Avoid showing dev hints for Python requirements (#4111)
Closes https://github.com/astral-sh/uv/issues/4096.
2024-06-06 19:58:30 +00:00
konsti
e4e2590076
Use union of requires-python in workspace (#4041)
Follow-up to #4016.

This exposes `Range` and `PubGrubSpecifier` from outside the resolver to
use pubgrub's union creating a dependency edge we don't really want.
2024-06-06 19:21:02 +00:00
konsti
a6f53e2aa4
Lock all packages in workspace (#4016)
When creating a lockfile, lock the combined dependencies for all
packages in a workspace. This make the lockfile independent of where you
are in the workspace.

Fixes #3983
2024-06-06 19:09:44 +00:00
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 = "0d26ce356c/typing_extensions-4.10.0.tar.gz"
- hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"
- size = 77558
-
- [[distribution.wheel]]
- url = "dc04a3ea60/typing_extensions-4.10.0-py3-none-any.whl"
- hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"
- size = 33926

+ sdist = { url = "0d26ce356c/typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb", size = 77558 }
+ wheel = [{ url = "dc04a3ea60/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