Most everyone has been pretty quiet, so I’ll make the first move. (Queen’s pawn to D4, obviously!)
I don’t think that the lockfile should include extras and groups. That idea should be deferred because it introduces many new unknowns.
I’ll share my reasoning, since I think that’s more valuable than my conclusion.
One thing I’ve been thinking about for the past week is that even with these values included, there will be use-cases which still demand multiple lock files for a single project.
The existing lockers I’ve tried allow packages included anywhere in the input to impact the entire resolution. That is, if I have project.dependencies = ["requests>2.0"]
and dependency-groups.group1 = ["requests<=2.2.0"]
, then in my lockfile I’ll get requests == 2.2.0
as the locked version.
This makes for fast “universal” locking behavior which supports most install scenarios. There’s a viable solution for requests
which satisfies multiple different install scenarios, so lock that one. It’s how these tools guarantee that as many combinations of extras and groups as possible are mutually installable. But it’s also not what a package maintainer wants if they define a test matrix which tests their project “with and without group1
installed” – they really want to test on “the latest and 2.2.0, in separate tests”.
Expand this problem out as necessary to find more complex or more compelling examples as you see fit. The point is that the user wants distinct resolutions here, but the lockers are optimized (right now) for cases in which you want compatible resolution. Different goals.
A question follows from this: “Can the lockers allow you to customize resolution to get different results?” And the answer is yes, at least somewhat. uv
has a config for declaring dependency groups incompatible, which allows them to resolve separately, but also means they can’t be installed into the same environment. That lets you customize resolution to say that “group1
and group2
are incompatible with one another, don’t try to lock them together”.
But that capability is a double-edged sword. If we push that idea down into the standardized lockfile format, then a request to install group1, group2
from a lockfile may succeed or fail depending on whether or not the two are compatible.
If the lockfile spec only supports locking a single scenario, consumers won’t have to contend with these sorts of issues yet. But if it supports groups and extras, then installers will need to support selecting extras, selecting groups, and the possibility that the selection isn’t installable. And we will still need multiple locks in order to support scenarios like “resolve first-order dependencies to the minimum compatible versions, but second order dependencies and further to the latest versions” (for which we can expect that the user is required to do some work to express themselves).
So installers will become more complex, the lockfile spec becomes more complex, but multiple locks per project remain a requirement in order to express the most complex scenarios.
I say all of this even though I would like support to arrive. My own use-cases would benefit a lot from having a unified lock with dependency group support. But I think it’s risky to declare that part of the initial spec. If each file describes a single scenario, I can still create a requirements-lock/
directory and put a bunch of lockfiles in there, one for each test scenario I want. And I’ll still end up with many fewer files than I currently have with pip-compile
, since lockfiles can handle markers and platform support more gracefully.