Change the definition of --locked to require satisfaction check#6102
Change the definition of --locked to require satisfaction check#6102charliermarsh merged 1 commit intomainfrom
--locked to require satisfaction check#6102Conversation
|
I'm now trying to think of a situation in which the user could change something (like a workspace requirement), and |
|
Anyway, I think this is another change that would reduce a lot of complexity for us while being basically the same for users. |
I'm not sure I understand this, shouldn't this change allow strictly more lockfiles to satisfy |
I don't think so, because before, if you failed |
|
Does that make sense? |
451c1cd to
370d990
Compare
|
I see, that makes sense. So now we're verifying against the requirements, not the new lockfile. |
|
Yeah, that's a fair description |
|
I'm not sure how this compares to changing the markers to not store the range restriction state. Also trying to think of an example where the requirements change but a resolution would have resulted in the same lockfile (so |
Yeah this is where I'm ending up too. |
ibraheemdev
left a comment
There was a problem hiding this comment.
I think the part about requires-dist making the lockfile change where it previously wouldn't is a little unfortunate, but if we decide to do that (separate from this PR) then this makes sense to me.
I'm wondering if this is really that big of a problem. If we don't go through |
|
Maybe just to show my hand a bit: I think this fast path is critical for |
|
Maybe one thing for me to think through tomorrow -- what happens when:
What do we reuse? Where are we being inefficient? |
|
The other thing we lost is user clones a repo and runs |
|
I think that’s unchanged, no? What’s different there? |
|
Sorry, you're right, that hasn't changed. Adding a dependency is where it changed. |
|
Yeah, adding a dependency (that was already in the lockfile, I think? But not explicit) changed. |
|
Any resolution that didn't require fetching versions of existing packages that were not in the lockfile changed. For example, adding a new dependency that did not affect the locked versions of any existing dependencies could use the prefilled index from the lockfile and only fetch the metadata for the new package. Not sure how big of an impact that optimization had though, and I think we can still make it in the future. |
BurntSushi
left a comment
There was a problem hiding this comment.
I think we should do this because it moves uv to a more conservative posture. But I do think we should improve on this in the future. Some specific thoughts:
The equality check is hard to get right. For example, it means that we can't ship #6076 without changing our marker representation, since the deserialized lockfile "loses" some of the internal marker state that gets accumulated during resolution.
Is this something that could also be fixed by a custom equality comparison?
The downside of this change is that there could be scenarios in which uv lock --locked fails even though the lockfile would actually work and the exact TOML would be unchanged. But... I think it's ok if --locked fails after the user modifies something?
I agree. Or at least, I think this is the right decision to make right now.
I'm now trying to think of a situation in which the user could change something (like a workspace requirement), and Lock::satisfies fails, but then the TOML is totally unchanged. Is that even possible anymore?
One example is:
- In
pyproject.toml, there is a dependencyfoo>=1.0. - In
uv.lock,foois locked to1.2. - I make a change to
pyproject.tomlby updating the dependency onfootofoo>=1.1.
This is a somewhat strained example, but it's definitely something I've done a few times in the Rust world where I realized my minimum version constraint was wrong (because I was depending on features in foo released in 1.1). So it's not like it never happens. But I think this is a case where Lock::satisfies will fail, but a re-resolve (assuming nothing in the world changed) should produce the same semantic uv.lock. (The actual TOML would be different because we write out the full requirements, and that changed, but the actual locked version that we install wouldn't change.)
But like, I don't necessarily think that is a major issue. Or at least, not a release blocking issue. Unless there are other more important use cases that I'm missing. That is, I think the worst thing that happens here is that folks might need to re-run uv lock in some cases where they might not otherwise have to.
|
👍 I agree with the above. (And yeah, the TOML would change in that format, but the locked dependencies would not.) |
Summary
This PR changes the definition of
--lockedfrom:To:
This is a subtle but important difference. Previous, if
Lock::satisfiesfailed, we would run a resolution, then doexisting_lock == lock. If the two weren't equal, and--lockedwas specified, we'd throw an error.The equality check is hard to get right. For example, it means that we can't ship #6076 without changing our marker representation, since the deserialized lockfile "loses" some of the internal marker state that gets accumulated during resolution.
The downside of this change is that there could be scenarios in which
uv lock --lockedfails even though the lockfile would actually work and the exact TOML would be unchanged. But... I think it's ok if--lockedfails after the user modifies something?