-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Document why we ban URLs from index dependencies #15929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -176,6 +176,38 @@ numpy==2.0.0; python_version >= "3.9" and python_version < "3.10" | |
| numpy==2.1.0; python_version >= "3.10" | ||
| ``` | ||
|
|
||
| ## URL dependencies | ||
|
|
||
| In uv, a dependency can either be a registry dependency, a package with a version specifier or the | ||
| plain package name, or a URL dependency, everything with a `{name} @ {url}` or a `git`,` url`, | ||
| `path`, or `workspace` source, or put differently, all Git, remote file, local file or local path | ||
| dependencies. | ||
|
|
||
| When a URL is declared for a package, uv pins the package to this URL, and the version this URL | ||
| implies. If there are two conflicting URLs for a package, the resolver errors, as a URL can only be | ||
| declared as something akin to an exact `==` pin, and not as list of URLs. A list of URLs is | ||
| supported through [flat indexes](../../concepts/indexes.md#flat-indexes) instead. | ||
|
|
||
| uv requires that URLs are either declared directly (in the project, in a workspace member, in a | ||
| constraint, or in an override, any location that is discovered directly), or by other URL | ||
|
konstin marked this conversation as resolved.
Outdated
|
||
| dependencies. uv discovers all URL dependencies and their transitive URL dependencies ahead of the | ||
| resolution and pins all packages to the URLs and the versions they imply. | ||
|
|
||
| uv does not allow URLs in index packages. This has two reasons: One is a security and predictability | ||
| aspect, that forbids registry distributions to point to non-registry distributions and helps | ||
| auditing which URls can be accessed. For example, when only using one index URL and no URL | ||
|
konstin marked this conversation as resolved.
Outdated
|
||
| dependencies, uv will not install any package from outside the index. | ||
|
|
||
| The other is that URLs can add additional versions to the resolution, which either breaks an | ||
| assumption of the incremental resolver or would require to always fetch the metadata for all | ||
| versions. Say the root package depends on foo, bar, and baz, all registry dependencies. foo depends | ||
| on `bar >= 2`, but bar only has version 1 on the index. With the incremental approach, this is an | ||
| error, foo cannot be fulfilled, there is a resolver error. If URLs on index packages were allowed, | ||
|
konstin marked this conversation as resolved.
Outdated
|
||
| it could be that there is a version of baz declares a dependency on baz-core and that has a version | ||
| that declares `bar @ https://example.com/bar-2-py3-none-any.whl` adding a version of bar that makes | ||
| requirements resolve. If a dependency can add new versions, discarding any version in the resolver | ||
| would require looking at all possible versions of all direct and transitive dependencies. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other words: this is a limitation of uv's resolver implementation. In order to keep resolution time (and memory usage I assume) reasonably low, it assumes that the version universe is fixed during resolution, and no new versions can be discovered during the process.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could theoretically make it possible by fetching everything ahead of time and checking, but having to check every version reachable ruins performance. iirc no package manager supports this, it's not really possible to write a performant tool if you can't be incremental, just from the cost of looking at all packages.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's hard to explain it with an example here to avoid having to explain the concept of resolution in the SAT sense and how you can't derive that a package-version in incompatible from a range of its dependency being exhaustively incompatible and how that's required to make both fast conclusions and to conclude failure for incompatible dependencies. |
||
|
|
||
| ## Prioritization | ||
|
|
||
| Prioritization is important for both performance and for better resolutions. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.