Commit Graph

223 Commits

Author SHA1 Message Date
Charlie Marsh bf79d985ee
Allow incompatible `requires-python` for source distributions with static metadata (#8768)
## Summary

At present, when we have a Python requirement and we see a wheel, we
verify that the Python requirement is compatible with the wheel. For
source distributions, though, we verify that both the Python requirement
_and_ the currently-installed version are compatible, because we assume
that we'll need to build the source distribution in order to get
metadata. However, we can often extract source distribution metadata
_without_ building (e.g., if there's a `pyproject.toml` with no dynamic
keys).

This PR thus modifies the source distribution handling to defer that
incompatibility ("We couldn't get metadata for this project, because it
has no static metadata and requires a higher Python version to run /
build") until we actually try to build the package. As a result, you can
now resolve source distribution-only packages using Python versions
below their `requires-python`, as long as they include static metadata.

Closes https://github.com/astral-sh/uv/issues/8767.
2024-11-03 19:03:55 +00:00
Andrew Gallant 58a9811881
fix bug where `python_version < '0'` could appear in a final resolution (#8759)
This PR fixes a bug where it was possible for dependencies to be
included in a final resolution with markers that always evaluate to
false. Specifically, `python_version < '0'`.

While we do filter based on Python markers during forking, it turns out
that the markers for each fork are "combined" *after* this filtering
step. But the process of combination can result in a more specific
marker that is always false for the configured Python requirement. This
could result in dependencies with markers that are always false (like
`python_version < '0'`) appearing in the resolution.

The first commit in this PR adds a regression test (with an undesirable
result), and the second commit fixes the regression and updates the
test.

Fixes #8676
2024-11-01 20:11:40 +00:00
konsti c1a0fb35e8
Simplify pep440 -> version ranges conversion (#8683) 2024-10-30 13:10:48 +01:00
konsti e5b8cdba70
Merge uv-pubgrub into uv-pep440 (#8669) 2024-10-29 20:15:18 +01:00
Charlie Marsh bfa84cd1ab
Fork when minimum Python version increases (#8628)
## Summary

This is a re-implementation of
https://github.com/astral-sh/uv/pull/4712, though is now seemingly much
simpler. This issue keeps coming up, and users have a workaround with
`tool.uv.environments`, but it's really a bug in the resolver.

Closes https://github.com/astral-sh/uv/issues/4668.
2024-10-28 09:48:04 -04:00
Charlie Marsh 5ab860be20 Rename dev dependencies to dependency groups in lockfile (#8391)
This is backwards compatible (we respect `dev-dependencies` as an
alias).

Part of https://github.com/astral-sh/uv/pull/8272.
2024-10-25 13:27:37 -05:00
konsti 32bba9f33b
Don't prefetch unreachable packages (#8246) 2024-10-18 13:44:24 +02:00
Charlie Marsh 4ca158931a
Show hint in resolution failure on `Forbidden` (`403`) or `Unauthorized` (`401`) (#8264)
## Summary

Closes https://github.com/astral-sh/uv/issues/8167.
2024-10-16 17:34:29 +00:00
Charlie Marsh 2153c6ac0d
Respect named `--index` and `--default-index` values in `tool.uv.sources` (#7910)
## Summary

If you pass a named index via the CLI, you can now reference it as a
named source. This required some surprisingly large refactors, since we
now need to be able to track whether a given index was provided on the
CLI vs. elsewhere (since, e.g., we don't want users to be able to
reference named indexes defined in global configuration).

Closes https://github.com/astral-sh/uv/issues/7899.
2024-10-15 23:56:24 +00:00
Charlie Marsh 9a76e47888
Allow multiple pinned indexes in `tool.uv.sources` (#7769)
## Summary

This PR lifts the restriction that a package must come from a single
index. For example, you can now do:

```toml
[project]
name = "project"
version = "0.1.0"
readme = "README.md"
requires-python = ">=3.12"
dependencies = ["jinja2"]

[tool.uv.sources]
jinja2 = [
    { index = "torch-cu118", marker = "sys_platform == 'darwin'"},
    { index = "torch-cu124", marker = "sys_platform != 'darwin'"},
]

[[tool.uv.index]]
name = "torch-cu118"
url = "https://download.pytorch.org/whl/cu118"

[[tool.uv.index]]
name = "torch-cu124"
url = "https://download.pytorch.org/whl/cu124"
```

The construction is very similar to the way we handle URLs today: you
can have multiple URLs for a given package, but they must appear in
disjoint forks. So most of the code is just adding that abstraction to
the resolver, following our handling of URLs.

Closes #7761.
2024-10-15 22:58:15 +00:00
Charlie Marsh 5b391770df
Add support for named and explicit indexes (#7481)
## Summary

This PR adds a first-class API for defining registry indexes, beyond our
existing `--index-url` and `--extra-index-url` setup.

Specifically, you now define indexes like so in a `uv.toml` or
`pyproject.toml` file:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
```

You can also provide indexes via `--index` and `UV_INDEX`, and override
the default index with `--default-index` and `UV_DEFAULT_INDEX`.

### Index priority

Indexes are prioritized in the order in which they're defined, such that
the first-defined index has highest priority.

Indexes are also inherited from parent configuration (e.g., the
user-level `uv.toml`), but are placed after any indexes in the current
project, matching our semantics for other array-based configuration
values.

You can mix `--index` and `--default-index` with the legacy
`--index-url` and `--extra-index-url` settings; the latter two are
merely treated as unnamed `[[tool.uv.index]]` entries.

### Index pinning

If an index includes a name (which is optional), it can then be
referenced via `tool.uv.sources`:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"

[tool.uv.sources]
torch = { index = "pytorch" }
```

If an index is marked as `explicit = true`, it can _only_ be used via
such references, and will never be searched implicitly:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
explicit = true

[tool.uv.sources]
torch = { index = "pytorch" }
```

Indexes defined outside of the current project (e.g., in the user-level
`uv.toml`) can _not_ be explicitly selected.

(As of now, we only support using a single index for a given
`tool.uv.sources` definition.)

### Default index

By default, we include PyPI as the default index. This remains true even
if the user defines a `[[tool.uv.index]]` -- PyPI is still used as a
fallback. You can mark an index as `default = true` to (1) disable the
use of PyPI, and (2) bump it to the bottom of the prioritized list, such
that it's used only if a package does not exist on a prior index:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"
default = true
```

### Name reuse

If a name is reused, the higher-priority index with that name is used,
while the lower-priority indexes are ignored entirely.

For example, given:

```toml
[[tool.uv.index]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cu121"

[[tool.uv.index]]
name = "pytorch"
url = "https://test.pypi.org/simple"
```

The `https://test.pypi.org/simple` index would be ignored entirely,
since it's lower-priority than `https://download.pytorch.org/whl/cu121`
but shares the same name.

Closes #171.

## Future work

- Users should be able to provide authentication for named indexes via
environment variables.
- `uv add` should automatically write `--index` entries to the
`pyproject.toml` file.
- Users should be able to provide multiple indexes for a given package,
stratified by platform:
```toml
[tool.uv.sources]
torch = [
  { index = "cpu", markers = "sys_platform == 'darwin'" },
  { index = "gpu", markers = "sys_platform != 'darwin'" },
]
```
- Users should be able to specify a proxy URL for a given index, to
avoid writing user-specific URLs to a lockfile:
```toml
[[tool.uv.index]]
name = "test"
url = "https://private.org/simple"
proxy = "http://<omitted>/pypi/simple"
```
2024-10-15 18:24:23 -04:00
Charlie Marsh c683191408
Don't recommend `--prerelease=allow` for source dist builds (#8192)
## Summary

Closes https://github.com/astral-sh/uv/issues/3686.
2024-10-14 21:04:30 -04:00
Charlie Marsh 14507a1793
Add `uv-` prefix to all internal crates (#7853)
## Summary

Brings more consistency to the repo and ensures that all crates
automatically show up in `--verbose` logging.
2024-10-01 20:15:32 -04:00
Charlie Marsh 1602b5c8d7
Remove unnecessary index location methods (#7826) 2024-10-01 04:44:53 +00:00
Charlie Marsh fe88c10813
Remove unused `thiserror` variants in resolver (#7717)
## Summary

While looking at something else, I noticed that these are not used.
2024-09-26 16:36:52 +00:00
Topher Anderson 84e5f6e871
Regression fix: don't prefetch source dists with unbounded lower-bound ranges (#7683)
#7226 modified the check to skip prefetching of source dists without
proper minimum-version bounds, and wound up flipping the boolean
expression. This change flips the some/none expression so that the
intended skip happens as expected.

Fixes #7680.
2024-09-25 08:35:19 -04:00
konsti 5da73a24cb
Rename `MetadataResolver` to `ResolutionMetadata` (#7661) 2024-09-24 16:25:19 +00:00
konsti 484717d42f
Split metadata parsing into a module (#7656) 2024-09-24 17:16:21 +02:00
Charlie Marsh b14696ca7c
Show a dedicated PubGrub hint for `--unsafe-best-match` (#7645)
## Summary

Closes https://github.com/astral-sh/uv/issues/5510.
2024-09-23 19:02:19 +00:00
Charlie Marsh 9a7262c360
Avoid batch prefetching for un-optimized registries (#7226)
## Summary

We now track the discovered `IndexCapabilities` for each `IndexUrl`. If
we learn that an index doesn't support range requests, we avoid doing
any batch prefetching.

Closes https://github.com/astral-sh/uv/issues/7221.
2024-09-09 15:46:19 -04:00
Charlie Marsh dcbaa1f486
Avoid iteration for singleton selections (#7195)
## Summary

If we have a singleton `Range`, we don't need to iterate over the map of
available ranges; instead, we can just get the singleton directly.

Closes #6131.
2024-09-09 13:43:57 +00:00
Charlie Marsh 7d49fbc753
Skip metadata fetch for `--no-deps` and `pip sync` (#7127)
## Summary

I think a better tradeoff here is to skip fetching metadata, even though
we can't validate the extras.

It will help with situations like
https://github.com/astral-sh/uv/issues/5073#issuecomment-2334235588 in
which, otherwise, we have to download the wheels twice.
2024-09-06 21:26:28 -04:00
Andrew Gallant 4ff057e108 uv-resolver: refactor how we deal with requires-python
This commit refactors how deal with `requires-python` so that instead of
simplifying markers of dependencies inside the resolver, we do it at the
edges of our system. When writing markers to output, we simplify when
there's an obvious `requires-python` context. And when reading markers
as input, we complexity markers with the relevant `requires-python`
constraint.
2024-09-03 18:41:15 -04:00
Andrew Gallant 94a0a0f2ee uv-resolver: rejigger 'trace_resolution'
When I first wrote this routine, it was intended to only emit a trace
for the final "unioned" resolution. But we actually moved that semantic
operation to the construction of the resolution *graph*. So there is no
unioned `Resolution` any more.

But this is still useful to see. So I changed this to just emit a trace
of *every* resolution right before constructing the graph.

It might be nice to also emit a trace of the unioned graph too. Or
perhaps we should do that instead if this proves too noisy. (Although
this is only emitted at TRACE level.)
2024-09-03 18:41:15 -04:00
Charlie Marsh 8eef1a2314
Use lower-bound semantics for all Python compatibility comparisons (#6882)
## Summary

Right now, we have slightly different `requires-python` semantics for
`-p 3.11` vs. `-p 3.11 --universal`, and slightly different (wrong)
semantics for how we compare against the _installed_ Python version
(which doesn't ignore upper bounds, but should).

This PR rips it all out and replaces it with consistent semantics across
`uv lock`, `uv pip compile -p 3.11`, and `uv pip compile -p 3.11
--universal`. We now always ignore upper bounds.

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

Closes https://github.com/astral-sh/uv/issues/5045.
2024-09-02 18:23:42 +00:00
Charlie Marsh 34d74501ac
Respect the user's upper-bound in `requires-python` (#6824)
## Summary

We now respect the user-provided upper-bound in for `requires-python`.
So, if the user has `requires-python = "==3.11.*"`, we won't explore
forks that have `python_version >= '3.12'`, for example.

However, we continue to _only_ compare the lower bounds when assessing
whether a dependency is compatible with a given Python range.

Closes https://github.com/astral-sh/uv/issues/6150.
2024-08-29 18:37:05 +00:00
Charlie Marsh a7850d2a1c
Use separate types to represent raw vs. resolver markers (#6646)
## Summary

This is similar to https://github.com/astral-sh/uv/pull/6171 but more
expansive... _Anywhere_ that we test requirements for platform
compatibility, we _need_ to respect the resolver-friendly markers. In
fixing the motivating issue (#6621), I also realized that we had a bunch
of bugs here around `pip install` with `--python-platform` and
`--python-version`, because we always performed our `satisfy` and `Plan`
operations on the interpreter's markers, not the adjusted markers!

Closes https://github.com/astral-sh/uv/issues/6621.
2024-08-26 18:00:21 +00:00
Zanie Blue baf17bee86
Avoid panicking when the resolver thread encounters a closed channel (#6182)
Closes https://github.com/astral-sh/uv/issues/6167

We've been seeing intermittent failures in CI, which we thought were
unexpected HTTP 401s but it actually looks like a panic when handling an
expected HTTP error. I believe the problem is that an early client error
can cause the channel to close and we crash when we unwrap the `send`.
2024-08-18 21:04:05 +00:00
Zanie Blue ea636bbe61
Simplify available package version ranges when the name includes markers or extras (#6162)
There were different `PubGrubPackage` types so they never matched the
available versions set! Luckily, the available versions are agnostic to
the markers and optional dependencies so we can just broaden to using
`PackageName` as a lookup key.

Addresses yet another complaint in
https://github.com/astral-sh/uv/issues/5046
2024-08-16 15:21:49 -05:00
Zanie Blue 89efe2491b
Improve display of resolution errors for workspace member conflicts with optional dependencies (#6123)
We have bad error messages for optional (extra) dependencies and
development dependencies in workspaces:

1. We weren't showing the full package, so we'd drop `:dev` and
`[extra]` by accident
2. We didn't include derived packages, e.g., `member[extra]` in tree
processing collapse operation, so we'd include extra clauses like the
ones we removed in #6092

Also

- Reverts
f0de4f71f2
— it turns out it wasn't quite correct and it didn't seem worth using
the custom incompatibility anymore.
- Fixes a bug in the display of `package:dev` which was not showing
`:dev` for some variants (see 94d8020b58)
2024-08-15 20:50:43 -05:00
Ibraheem Ahmed e6ddce0246
Normalize `python_version` markers to `python_full_version` (#6126)
## Summary

Normalize all `python_version` markers to their equivalent
`python_full_version` form. This avoids false positives in forking
because we currently cannot detect any relationships between the two
forms. It also avoids subtle bugs due to the truncating semantics of
`python_version`. For example, given `requires-python = ">3.12"`, we
currently simplify the marker `python_version <= 3.12` to `false`.
However, the version `3.12.1` will be truncated to `3.12` for
`python_version` comparisons, and thus it satisfies the python
requirement and evaluates to `true`.

It is possible to simplify back to `python_version` when writing markers
to the lockfile. However, the equivalent `python_full_version` markers
are often clearer and easier to simplify, so I lean towards leaving them
as `python_full_version`.

There are *a lot* of snapshot updates from this change. I'd like more
eyes on the transformation logic in `python_version_to_full_version` to
ensure that they are all correct.

Resolves https://github.com/astral-sh/uv/issues/6125.
2024-08-15 21:42:15 -04:00
Charlie Marsh 3ee865831f
Change `debug!` back to `trace!` in filtering (#6117)
## Summary

I changed this for debugging and forgot to revert. Not awful but
probably a little much for `debug!`.
2024-08-15 16:07:02 +00:00
Charlie Marsh 4d13b525ef
Avoid cloning requirement for unchanged markers (#6116)
## Summary

Small optimization.
2024-08-15 15:58:20 +00:00
Charlie Marsh fe0b873352
Always narrow markers by Python version (#6076)
## Summary

Using https://github.com/astral-sh/uv/issues/6064 as a motivating
example: at present, on main, we're not properly propagating the
`Requires-Python` simplifications. In that case, for example, we end up
solving for a branch with `python_version < 3.11`, and a branch `>=
3.11`, even though `Requires-Python` is `>=3.11`. Later, when we get to
the graph, we apply version simplification based on `Requires-Python`,
which causes us to _remove_ the `python_version < 3.11` markers
entirely, leaving us with duplicate dependencies for `pylint`.

This PR instead tries to ensure that we always apply this narrowing to
requirements and forks, so that we don't need to apply the same
simplification when constructing the graph at all.

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

Closes #6059.
2024-08-15 11:50:00 -04:00
Andrew Gallant 3187dc1a2f uv-resolver: remove code that was intended to be removed
In particular, I added this as a hack to avoid a kinda of
instability that was caused by our marker code not correctly
detecting markers that were always false. But that has since
been fixed.

Removing this code doesn't change any tests. Arguably it
should be possible to come up with a test that failed with
this hack inserted but succeeded without it. In particular,
with this hack, new forks were being prevented from being
added even when they ought to be added, e.g., when preferences
get updated.
2024-08-15 05:25:55 -07:00
Zanie Blue 2e3e6a01aa
Improve resolver error messages referencing workspace members (#6092)
An extension of #6090 that replaces #6066.

In brief, 

1. Workspace member names are passed to the resolver for no solution
errors
2. There is a new derivation tree pre-processing step that trims
`NoVersion` incompatibilities for workspace members from the derivation
tree. This avoids showing redundant clauses like `Because only
bird==0.1.0 is available and bird==0.1.0 depends on anyio==4.3.0, we can
conclude that all versions of bird depend on anyio==4.3.0.`. As a minor
note, we use a custom incompatibility kind to mark these
incompatibilities at resolution-time instead of afterwards.
3. Root dependencies on workspace members say `your workspace requires
bird` rather than `you require bird`
4. Workspace member package display omits the version, e.g., `bird`
instead of `bird==0.1.0`
5. Instead of reporting a workspace member as unusable we note that its
requirements cannot be solved, e.g., `bird's requirements are
unsatisfiable` instead of `bird cannot be used`.
6. Instead of saying `your requirements are unsatisfiable` we say `your
workspace's requirements are unsatisfiable` when in a workspace, since
we're not in a "provide direct requirements" paradigm.

As an annoying but minor implementation detail, `PackageRange` now
requires access to the `PubGrubReportFormatter` so it can determine if
it is formatting a workspace member or not. We could probably improve
the abstractions in the future.

As a follow-up, we should additional special casing for "single project"
workspaces to avoid mention of the workspace concept in simple projects.
However, it looks like this will require additional tree manipulations
so I'm going to keep it separate.
2024-08-15 02:41:31 +00:00
Charlie Marsh e3f345ce09
Validate lockfile (rather than re-resolve) in `uv lock` (#6091)
## Summary

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

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

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

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

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

Closes https://github.com/astral-sh/uv/issues/6063.
2024-08-14 20:00:15 -04:00
Zanie Blue 359f39ca0f
Avoid displaying "failed to download" on build failures for local source distributions (#6075)
Especially with workspace members (e.g., [this new test
case](https://github.com/astral-sh/uv/pull/6073/files#diff-273076013b4f5a8139defd5dcd24f5d1eb91c0266dceb4448fdeddceb79f7738R1377-R1379)),
I find it very confusing that we say we failed to download these
distributions.
2024-08-14 17:27:55 -05:00
Charlie Marsh 9de3c945f6
Remove `same-graph` merging in resolver (#6077)
## Summary

This was added in https://github.com/astral-sh/uv/pull/5405 but is now
the cause of an instability in `github_wikidata_bot`. Specifically, on
the initial run, we fork in `pydantic==2.8.2`, via:

```
Requires-Dist: typing-extensions>=4.12.2; python_version >= '3.13'
Requires-Dist: typing-extensions>=4.6.1; python_version < '3.13'
```

In the end, we resolve a single version of `typing-extensions`
(`4.12.2`)... But we don't recognize the two resolutions as the "same
graph", because we propagate the fork markers, and so the "edges" have
different markers on them...

In the second run through, when we have the forks in advance, we don't
split on Pydantic... We just try to solve from the root with the current
forks. This is fundamentally different and I fear it will be the cause
of many instabilities. But removing this graph check fixes the proximate
issue.

I don't really understand why this was added since there was no test
coverage in the PR.
2024-08-14 14:06:18 +00:00
Charlie Marsh 4a902a7ca1
Propagate fork markers to extras (#6065)
## Summary

When constructing the `Resolution`, we only propagated the fork markers
to the package node, but not the extras node. This led to cases in which
an extra could be included unconditionally or otherwise diverge from the
base package version.

Closes https://github.com/astral-sh/uv/issues/6062.
2024-08-14 09:55:39 -04:00
Charlie Marsh 8c8f723005
Store `environment-markers` in solve order (#6078)
## Summary

Right now, we store the environment markers in a `BTreeSet` -- so
they're sorted, but the sort doesn't really tell us anything. I think we
should instead store them in the order in which we solved. I thought
this might fix an instability (it didn't), but I think it's still good
to ensure we solve in the same order.

I also changed from `Option<Vec>` to just `Vec`, since there was no
distinction between `None` and empty.
2024-08-14 09:20:12 -04:00
Andrew Gallant 04b7cf894a uv-resolver: rewrite forking to be based on overlapping markers
Closes #4732
2024-08-13 08:35:46 -07:00
Ibraheem Ahmed fb5c3bb918
Remove uses of `Option<MarkerTree>` in `ResolutionGraph` (#6035)
## Summary

Missed this one in https://github.com/astral-sh/uv/pull/5978.

Resolves https://github.com/astral-sh/uv/issues/5902.
2024-08-12 10:31:07 -04:00
Ibraheem Ahmed f5110f7b5e
Remove uses of `Option<MarkerTree>` (#5978)
## Summary

Follow up to https://github.com/astral-sh/uv/pull/5898. This should fix
some of the failures in https://github.com/astral-sh/uv/pull/5887 where
`uv lock --locked` is failing due to `Some(true)` and `None` markers not
comparing equal.
2024-08-10 13:23:29 -04:00
konsti a129cf7d7e
Warn when there are missing bounds on transitive deps in lowest (#5953)
Warn when there are missing bounds on transitive dependencies with
`--resolution lowest`.

Implemented as a lazy resolution graph check. Dev deps are odd because
they are missing the edge from the root that extras have (they are
currently orphans in the resolution graph), but this is more complex to
solve properly because we can put dev dep information in a `Requirement`
so i special cased them here.

Closes #2797
Should help with #1718

---------

Co-authored-by: Ibraheem Ahmed <ibraheem@ibraheem.ca>
2024-08-09 17:55:17 +00:00
Ibraheem Ahmed ffd18cc75d
Implement marker trees using algebraic decision diagrams (#5898)
## Summary

This PR rewrites the `MarkerTree` type to use algebraic decision
diagrams (ADD). This has many benefits:
- The diagram is canonical for a given marker function. It is impossible
to create two functionally equivalent marker trees that don't refer to
the same underlying ADD. This also means that any trivially true or
unsatisfiable markers are represented by the same constants.
- The diagram can handle complex operations (conjunction/disjunction) in
polynomial time, as well as constant-time negation.
- The diagram can be converted to a simplified DNF form for user-facing
output.

The new representation gives us a lot more confidence in our marker
operations and simplification, which is proving to be very important
(see https://github.com/astral-sh/uv/pull/5733 and
https://github.com/astral-sh/uv/pull/5163).

Unfortunately, it is not easy to split this PR into multiple commits
because it is a large rewrite of the `marker` module. I'd suggest
reading through the `marker/algebra.rs`, `marker/simplify.rs`, and
`marker/tree.rs` files for the new implementation, as well as the
updated snapshots to verify how the new simplification rules work in
practice. However, a few other things were changed:
- [We now use release-only comparisons for `python_full_version`, where
we previously only did for
`python_version`](https://github.com/astral-sh/uv/blob/ibraheem/canonical-markers/crates/pep508-rs/src/marker/algebra.rs#L522).
I'm unsure how marker operations should work in the presence of
pre-release versions if we decide that this is incorrect.
- [Meaningless marker expressions are now
ignored](https://github.com/astral-sh/uv/blob/ibraheem/canonical-markers/crates/pep508-rs/src/marker/parse.rs#L502).
This means that a marker such as `'x' == 'x'` will always evaluate to
`true` (as if the expression did not exist), whereas we previously
treated this as always `false`. It's negation however, remains `false`.
- [Unsatisfiable markers are written as `python_version <
'0'`](https://github.com/astral-sh/uv/blob/ibraheem/canonical-markers/crates/pep508-rs/src/marker/tree.rs#L1329).
- The `PubGrubSpecifier` type has been moved to the new `uv-pubgrub`
crate, shared by `pep508-rs` and `uv-resolver`. `pep508-rs` also depends
on the `pubgrub` crate for the `Range` type, we probably want to move
`pubgrub::Range` into a separate crate to break this, but I don't think
that should block this PR (cc @konstin).

There is still some remaining work here that I decided to leave for now
for the sake of unblocking some of the related work on the resolver.
- We still use `Option<MarkerTree>` throughout uv, which is unnecessary
now that `MarkerTree::TRUE` is canonical.
- The `MarkerTree` type is now interned globally and can potentially
implement `Copy`. However, it's unclear if we want to add more
information to marker trees that would make it `!Copy`. For example, we
may wish to attach extra and requires-python environment information to
avoid simplifying after construction.
- We don't currently combine `python_full_version` and `python_version`
markers.
- I also have not spent too much time investigating performance and
there is probably some low-hanging fruit. Many of the test cases I did
run actually saw large performance improvements due to the markers being
simplified internally, reducing the stress on the old `normalize`
routine, especially for the extremely large markers seen in
`transformers` and other projects.

Resolves https://github.com/astral-sh/uv/issues/5660,
https://github.com/astral-sh/uv/issues/5179.
2024-08-09 13:40:02 -04:00
Charlie Marsh 32f09d86b3
Prefetch metadata in `--no-deps` mode (#5918)
## Summary

This _used_ to be true but we now require fetching metadata for all
distributions even with `--no-deps` since, e.g., we validate that any
declared extras exist.
2024-08-08 12:35:15 -04:00
Ibraheem Ahmed e651e67f29
Support overlapping local and non-local requirements in forks (#5812)
## Summary

This fixes a bug introduced by
https://github.com/astral-sh/uv/pull/5232. It turns out that the
`universal_disjoint_base_or_local_requirement` test does not actually do
what it was meant to because of the incorrect python requirement. With a
valid python requirement, it fails on `main`. The problem is that we try
to exclude the original base version from the range of allowed versions
to try and prefer local versions. However, in the test, there is a
branch that depends on the non-local version, with no applicable local
in its fork. We should remove this exclusion as prioritization is
handled by the candidate resolver.
2024-08-06 12:04:35 -04:00
Charlie Marsh b26794bf6f
Remove double-proxy nodes in error reporting (#5738)
## Summary

If _both_ nodes in the derivation tree are proxies, we need to remove
the _entire_ node. So, the function now returns an `Option<Tree>`
instead of taking `&mut Tree`.

Closes https://github.com/astral-sh/uv/issues/5618.
2024-08-02 21:27:07 +00:00
konsti 38c6033010
Use fork markers and fork preferences in resolution with lockfile (#5481)
By resolving for each fork from the lockfile individually and by adding
using preferences for the current fork, we solve the instability #5180.
I've tested the locally and will add the packse test scenarios upstack.

Part of
https://github.com/astral-sh/uv/issues/5180#issuecomment-2247696198
2024-07-31 15:18:58 +00:00