Skip to content

Apply lockfile marker normalization for fork markers#18116

Merged
konstin merged 1 commit intomainfrom
konsti/comsimplifigoration-of-fork-markers
Feb 24, 2026
Merged

Apply lockfile marker normalization for fork markers#18116
konstin merged 1 commit intomainfrom
konsti/comsimplifigoration-of-fork-markers

Conversation

@konstin
Copy link
Member

@konstin konstin commented Feb 20, 2026

While dependency markers get a roundtrip through simplify/complexify (crates/uv-resolver/src/lock/mod.rs#L4846-L4848, #15994), this treatment was missing for fork markers, causing errors with --locked --refresh on a fresh lockfile.

Fixes #16839
Closes #18024

While dependency markers get a roundtrip through simplify/complexify (https://github.com/astral-sh/uv/blob/3223b1c39f8011a4460f2b5d56ace19e5d26e16d/crates/uv-resolver/src/lock/mod.rs#L4846-L4848), this treatment was missing for fork markers, causing errors with `--locked --refresh` on a fresh lockfile.

Fixes #16839
Closes #18024
@konstin konstin added the bug Something isn't working label Feb 20, 2026
@konstin
Copy link
Member Author

konstin commented Feb 20, 2026

@BurntSushi I tagged you for expertise on simplify/complexify; I don't have a full understanding of when we do which I one (and sometimes both in normalization pass), I've basically just copied the approach from dependency markers to fork markers here.

@charliermarsh
Copy link
Member

Is it not sufficient to (1) store simplified markers and (2) ensure we always compare the simplified markers here?

zaniebot pushed a commit to zaniebot/uv that referenced this pull request Feb 24, 2026
…change detection

Instead of normalizing fork markers via a simplify/complexify round-trip
(as proposed in astral-sh#18116), store both simplified and complexified forms in a
new `ForkMarkers` type. PartialEq compares the simplified forms, ensuring
markers from the resolver match markers deserialized from the lockfile
regardless of whether they've been through a requires-python round-trip.

This follows the same pattern as `Dependency`, which stores both
`simplified_marker` and `complexified_marker`.

Fixes astral-sh#16839
Closes astral-sh#18024

https://claude.ai/code/session_017Wu3GxDzMrmiymfDHiXHBq
@zanieb
Copy link
Member

zanieb commented Feb 24, 2026

That'd look like main...zaniebot:claude/investigate-uv-pr-H6fIZ

@konstin
Copy link
Member Author

konstin commented Feb 24, 2026

Is it not sufficient to (1) store simplified markers and (2) ensure we always compare the simplified markers here?

I don't follow, isn't that what this PR does?

Copy link
Member

@BurntSushi BurntSushi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this LGTM in the sense that it does match what we do elsewhere.

.iter()
.map(|marker| {
let simplified = SimplifiedMarkerTree::new(&requires_python, marker.combined());
UniversalMarker::from_combined(simplified.into_marker(&requires_python))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what confuses me is that deserializing a lock file is already doing this step?

let fork_markers = wire
.fork_markers
.into_iter()
.map(|simplified_marker| simplified_marker.into_marker(&wire.requires_python))
.map(UniversalMarker::from_combined)
.collect();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bug in #16839 is that we compare the resolver output to the deserialized output, and then see a mismatch, even if there was no change, as the one from the lockfile had a roundtrip through complexify/simplify, but the one from the resolver didn't.

};
// Normalize fork markers with a simplify/complexify round-trip through
// `requires-python`. This ensures markers from the resolver (which don't include
// `requires-python` bounds) match markers deserialized from the lockfile (which get
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding/memory is that "complexified" markers are what we use inside the resolver. That is, "simplified" markers are really only a thing in the context of writing a lock file whose markers are simplified given the context of a requires-python. But those simplified markers can't really be used on their own, because they lack the constraints that would otherwise be present with requires-python.

@charliermarsh
Copy link
Member

(Defer to Andrew's review.)

Copy link
Contributor

@EliteTK EliteTK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we discussed this on Discord it seemed to make sense and it does indeed now match the other code.

@konstin konstin merged commit 55cfaf9 into main Feb 24, 2026
53 checks passed
@konstin konstin deleted the konsti/comsimplifigoration-of-fork-markers branch February 24, 2026 16:43
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Feb 25, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [uv](https://github.com/astral-sh/uv) | patch | `0.10.4` → `0.10.6` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (uv)</summary>

### [`v0.10.6`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0106)

[Compare Source](astral-sh/uv@0.10.5...0.10.6)

Released on 2026-02-24.

##### Bug fixes

- Apply lockfile marker normalization for fork markers ([#&#8203;18116](astral-sh/uv#18116))
- Fix Python version selection for scripts with a `requires-python` conflicting with `.python-version` ([#&#8203;18097](astral-sh/uv#18097))
- Preserve file permissions when using reflinks on Linux ([#&#8203;18187](astral-sh/uv#18187))

##### Documentation

- Remove verbose documentation from optional dependencies help text ([#&#8203;18180](astral-sh/uv#18180))

### [`v0.10.5`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0105)

[Compare Source](astral-sh/uv@0.10.4...0.10.5)

Released on 2026-02-23.

##### Enhancements

- Add hint when named index is found in a parent config file ([#&#8203;18087](astral-sh/uv#18087))
- Add warning for `uv lock --frozen` ([#&#8203;17859](astral-sh/uv#17859))
- Attempt to use reflinks by default on Linux ([#&#8203;18117](astral-sh/uv#18117))
- Fallback to hardlinks after reflink failure before copying ([#&#8203;18104](astral-sh/uv#18104))
- Filter `pylock.toml` wheels by tags and `requires-python` ([#&#8203;18081](astral-sh/uv#18081))
- Validate wheel filenames are normalized during `uv publish` ([#&#8203;17783](astral-sh/uv#17783))
- Fix message when `exclude-newer` invalidates the lock file ([#&#8203;18100](astral-sh/uv#18100))
- Change the missing files log level to debug ([#&#8203;18075](astral-sh/uv#18075))

##### Performance

- Improve performance of repeated conflicts with an extra ([#&#8203;18094](astral-sh/uv#18094))

##### Bug fixes

- Fix `--no-emit-workspace` with `--all-packages` on single-member workspaces ([#&#8203;18098](astral-sh/uv#18098))
- Fix `UV_NO_DEFAULT_GROUPS` rejecting truthy values like `1` ([#&#8203;18057](astral-sh/uv#18057))
- Fix iOS detection ([#&#8203;17973](astral-sh/uv#17973))
- Propagate project-level conflicts to package extras ([#&#8203;18096](astral-sh/uv#18096))
- Use a global build concurrency semaphore ([#&#8203;18054](astral-sh/uv#18054))

##### Documentation

- Update documentation heading for environment variable files ([#&#8203;18122](astral-sh/uv#18122))
- Fix comment about `uv export` formats ([#&#8203;17900](astral-sh/uv#17900))
- Make it clear that Windows is supported in user- and system- level configuration docs ([#&#8203;18106](astral-sh/uv#18106))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4zMS4xIiwidXBkYXRlZEluVmVyIjoiNDMuMzEuOSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6OnBhdGNoIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uv lock --upgrade --dry-run giving "Lockfile changes detected" despite no changes

5 participants