db371560bc
To enforce the 100 character line limit in markdown files introduced in https://github.com/astral-sh/uv/pull/5635, and to automate the formatting of markdown files, i've added prettier and formatted our markdown files with it. I've excluded the changelog and the generated references documentation from this for having too many changes, but we can also include them. I'm not particular on which style we use. My main motivations are (major) not having to reflow markdown files myself anymore and (minor) consistence between all markdown files. I've chosen prettier for similar reason as we chose black, it's a single good style that's automated and shared in the community. I do prefer prettier's style of not breaking inside of a link name though. This PR is in two parts, the first adds prettier to CI and documents using it, while the second actually formats the docs. When merge conflicts arise, we can drop the last commit and regenerate it with `npx prettier --prose-wrap always --write BENCHMARKS.md CONTRIBUTING.md README.md STYLE.md docs/*.md docs/concepts/**/*.md docs/guides/**/*.md docs/pip/**/*.md`. --------- Co-authored-by: Zanie Blue <contact@zanie.dev>
163 lines
7.3 KiB
Markdown
163 lines
7.3 KiB
Markdown
# Resolution
|
|
|
|
## Resolution strategy
|
|
|
|
By default, uv follows the standard Python dependency resolution strategy of preferring the latest
|
|
compatible version of each package. For example, `uv pip install flask>=2.0.0` will install the
|
|
latest version of Flask (at time of writing: `3.0.0`).
|
|
|
|
However, uv's resolution strategy can be configured to support alternative workflows. With
|
|
`--resolution lowest`, uv will install the **lowest** compatible versions for all dependencies, both
|
|
**direct** and **transitive**. Alternatively, `--resolution lowest-direct` will opt for the
|
|
**lowest** compatible versions for all **direct** dependencies, while using the **latest**
|
|
compatible versions for all **transitive** dependencies. This distinction can be particularly useful
|
|
for library authors who wish to test against the lowest supported versions of direct dependencies
|
|
without restricting the versions of transitive dependencies.
|
|
|
|
For example, given the following `requirements.in` file:
|
|
|
|
```text title="requirements.in"
|
|
flask>=2.0.0
|
|
```
|
|
|
|
Running `uv pip compile requirements.in` would produce the following `requirements.txt` file:
|
|
|
|
```text title="requirements.txt"
|
|
# This file was autogenerated by uv via the following command:
|
|
# uv pip compile requirements.in
|
|
blinker==1.7.0
|
|
# via flask
|
|
click==8.1.7
|
|
# via flask
|
|
flask==3.0.0
|
|
itsdangerous==2.1.2
|
|
# via flask
|
|
jinja2==3.1.2
|
|
# via flask
|
|
markupsafe==2.1.3
|
|
# via
|
|
# jinja2
|
|
# werkzeug
|
|
werkzeug==3.0.1
|
|
# via flask
|
|
```
|
|
|
|
However, `uv pip compile --resolution lowest requirements.in` would instead produce:
|
|
|
|
```text title="requirements.in"
|
|
# This file was autogenerated by uv via the following command:
|
|
# uv pip compile requirements.in --resolution lowest
|
|
click==7.1.2
|
|
# via flask
|
|
flask==2.0.0
|
|
itsdangerous==2.0.0
|
|
# via flask
|
|
jinja2==3.0.0
|
|
# via flask
|
|
markupsafe==2.0.0
|
|
# via jinja2
|
|
werkzeug==2.0.0
|
|
# via flask
|
|
```
|
|
|
|
## Pre-release handling
|
|
|
|
By default, uv will accept pre-release versions during dependency resolution in two cases:
|
|
|
|
1. If the package is a direct dependency, and its version markers include a pre-release specifier
|
|
(e.g., `flask>=2.0.0rc1`).
|
|
1. If _all_ published versions of a package are pre-releases.
|
|
|
|
If dependency resolution fails due to a transitive pre-release, uv will prompt the user to re-run
|
|
with `--prerelease allow`, to allow pre-releases for all dependencies.
|
|
|
|
Alternatively, you can add the transitive dependency to your `requirements.in` file with a
|
|
pre-release specifier (e.g., `flask>=2.0.0rc1`) to opt in to pre-release support for that specific
|
|
dependency.
|
|
|
|
Pre-releases are
|
|
[notoriously difficult](https://pubgrub-rs-guide.netlify.app/limitations/prerelease_versions) to
|
|
model, and are a frequent source of bugs in other packaging tools. uv's pre-release handling is
|
|
_intentionally_ limited and _intentionally_ requires user opt-in for pre-releases, to ensure
|
|
correctness.
|
|
|
|
For more, see ["Pre-release compatibility"](../pip/compatibility.md#pre-release-compatibility)
|
|
|
|
## Dependency overrides
|
|
|
|
Historically, `pip` has supported "constraints" (`-c constraints.txt`), which allows users to narrow
|
|
the set of acceptable versions for a given package.
|
|
|
|
uv supports constraints, but also takes this concept further by allowing users to _override_ the
|
|
acceptable versions of a package across the dependency tree via overrides
|
|
(`--override overrides.txt`).
|
|
|
|
In short, overrides allow the user to lie to the resolver by overriding the declared dependencies of
|
|
a package. Overrides are a useful last resort for cases in which the user knows that a dependency is
|
|
compatible with a newer version of a package than the package declares, but the package has not yet
|
|
been updated to declare that compatibility.
|
|
|
|
For example, if a transitive dependency declares `pydantic>=1.0,<2.0`, but the user knows that the
|
|
package is compatible with `pydantic>=2.0`, the user can override the declared dependency with
|
|
`pydantic>=2.0,<3` to allow the resolver to continue.
|
|
|
|
While constraints are purely _additive_, and thus cannot _expand_ the set of acceptable versions for
|
|
a package, overrides _can_ expand the set of acceptable versions for a package, providing an escape
|
|
hatch for erroneous upper version bounds.
|
|
|
|
## Multi-platform resolution
|
|
|
|
By default, uv's `pip-compile` command produces a resolution that's known to be compatible with the
|
|
current platform and Python version.
|
|
|
|
uv also supports a machine agnostic resolution. uv supports writing multiplatform resolutions in
|
|
both a `requirements.txt` format and uv-specific (`uv.lock`) format.
|
|
|
|
If using uv's `pip compile`, the `--universal` flag will generate a resolution that is compatible
|
|
with all operating systems, architectures, and Python implementations. In universal mode, the
|
|
current Python version (or provided `--python-version`) will be treated as a lower bound. For
|
|
example, `--universal --python-version 3.7` would produce a universal resolution for Python 3.7 and
|
|
later.
|
|
|
|
If using uv's [project](../guides/projects.md) interface, the machine agnostic resolution will be
|
|
used automatically and a `uv.lock` file will be created. The lockfile can also be created with an
|
|
explicit `uv lock` invocation.
|
|
|
|
uv also supports resolving for specific alternate platforms and Python versions via the
|
|
`--python-platform` and `--python-version` command line arguments.
|
|
|
|
For example, if you're running uv on macOS, but want to resolve for Linux, you can run
|
|
`uv pip compile --python-platform linux requirements.in` to produce a `manylinux2014`-compatible
|
|
resolution.
|
|
|
|
Similarly, if you're running uv on Python 3.9, but want to resolve for Python 3.8, you can run
|
|
`uv pip compile --python-version 3.8 requirements.in` to produce a Python 3.8-compatible resolution.
|
|
|
|
The `--python-platform` and `--python-version` arguments can be combined to produce a resolution for
|
|
a specific platform and Python version, enabling users to generate multiple lockfiles for different
|
|
environments from a single machine.
|
|
|
|
!!! note
|
|
|
|
Python's environment markers expose far more information about the current machine
|
|
than can be expressed by a simple `--python-platform` argument. For example, the `platform_version` marker
|
|
on macOS includes the time at which the kernel was built, which can (in theory) be encoded in
|
|
package requirements. uv's resolver makes a best-effort attempt to generate a resolution that is
|
|
compatible with any machine running on the target `--python-platform`, which should be sufficient for
|
|
most use cases, but may lose fidelity for complex package and platform combinations.
|
|
|
|
## Time-restricted reproducible resolutions
|
|
|
|
uv supports an `--exclude-newer` option to limit resolution to distributions published before a
|
|
specific date, allowing reproduction of installations regardless of new package releases. The date
|
|
may be specified as an [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) timestamp (e.g.,
|
|
`2006-12-02T02:07:43Z`) or UTC date in the same format (e.g., `2006-12-02`).
|
|
|
|
Note the package index must support the `upload-time` field as specified in
|
|
[`PEP 700`](https://peps.python.org/pep-0700/). If the field is not present for a given
|
|
distribution, the distribution will be treated as unavailable.
|
|
|
|
To ensure reproducibility, messages for unsatisfiable resolutions will not mention that
|
|
distributions were excluded due to the `--exclude-newer` flag — newer distributions will be treated
|
|
as if they do not exist.
|