From 4e82db093a7983265eecfddecf9b1e3cf20e79a4 Mon Sep 17 00:00:00 2001 From: konsti Date: Fri, 23 Aug 2024 22:28:39 +0200 Subject: [PATCH] Document why we do lower bounds (#6516) Document in the resolution concept documentation why we add lower bounds --------- Co-authored-by: Zanie Blue --- docs/concepts/resolution.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/concepts/resolution.md b/docs/concepts/resolution.md index a1dcd1a20..57c0c1475 100644 --- a/docs/concepts/resolution.md +++ b/docs/concepts/resolution.md @@ -144,8 +144,8 @@ is requested or an upgrade is explicitly requested with `--upgrade`. By default, uv tries to use the latest version of each package. For example, `uv pip install flask>=2.0.0` will install the latest version of Flask, e.g., 3.0.0. If `flask>=2.0.0` is a dependency of the project, only `flask` 3.0.0 will be used. This is important, -for example, because running tests will not check that the the project is actually compatible with -its stated lower bound of `flask` 2.0.0. +for example, because running tests will not check that the project is actually compatible with its +stated lower bound of `flask` 2.0.0. With `--resolution lowest`, uv will install the lowest possible version for all dependencies, both direct and indirect (transitive). Alternatively, `--resolution lowest-direct` will use the lowest @@ -258,6 +258,27 @@ If multiple overrides are provided for the same package, they must be differenti [markers](#platform-markers). If a package has a dependency with a marker, it is replaced unconditionally when using overrides — it does not matter if the marker evaluates to true or false. +## Lower bounds + +By default, `uv add` adds lower bounds to dependencies and, when using uv to manage projects, uv +will warn if direct dependencies don't have lower bound. + +Lower bounds are not critical in the "happy path", but they are important for cases where there are +dependency conflicts. For example, consider a project that requires two packages and those packages +have conflicting dependencies. The resolver needs to check all combinations of all versions within +the constraints for the two packages — if all of them conflict, an error is reported because the +dependencies are not satisfiable. If there are no lower bounds, the resolver can (and often will) +backtrack down to the oldest version of a package. This isn't only problematic because it's slow, +the old version of the package often fails to build, or the resolver can end up picking a version +that's old enough that it doesn't depend on the conflicting package, but also doesn't work with your +code. + +Lower bounds are particularly critical when writing a library. It's important to declare the lowest +version for each dependency that your library works with, and to validate that the bounds are +correct — testing with [`--resolution lowest` or `resolution lowest-direct`](#resolution-strategy). +Otherwise, a user may receive an old, incompatible version of one of your library's dependencies and +the library will fail with an unexpected error. + ## Reproducible resolutions uv supports an `--exclude-newer` option to limit resolution to distributions published before a