Skip to content

fix: locate pre-commit config edits with exact source marks (#64) - #79

Draft
GabDug wants to merge 1 commit into
mainfrom
fix/64-exact-yaml-positions
Draft

GabDug wants to merge 1 commit into
mainfrom
fix/64-exact-yaml-positions

Conversation

@GabDug

@GabDug GabDug commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Fixes #64.

strictyaml's end_line counts YAML nodes, not source lines. A multi-line flow
sequence is one node over several lines, so every line number after it is too
small and we edit the wrong line — silently, since the old text isn't there.

      - id: check-jsonschema
        args: [              # 4 source lines, 1 node
            "--no-cache",
          ]

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.0.0              # never updated

Fix: take line and column from ruamel's lc marks instead. They come from the
lexer, so they are exact. strictyaml vendors ruamel, so no new dependency.

  • Edits are applied rightmost first, so two values on one line don't shift each
    other's columns.
  • Each edit checks the old text is really at that position, and raises if not.
  • document_start_offset and the difflib change count are gone.
  • New fixture and tests for the multi-line flow layout.

Notes: strictyaml still validates the schema, ruamel only gives
positions. We patch the text rather than re-dump, which would reformat the whole
file. Replacement starts at the column instead of startswith, because ruamel
points at the opening quote of a quoted scalar.

`update_pre_commit_repo_versions` found the line to rewrite from strictyaml's
`end_line` plus a hand-computed document offset. `end_line` counts logical
nodes rather than physical lines, so it drifts by `lines - 1` past any
multi-line flow sequence: the rewrite landed on the wrong line, the
`.replace()` matched nothing, and the write aborted with "No changes to
write, this should not happen".

Take positions from a ruamel round-trip parse instead, whose `lc` marks come
from the lexer and are absolute. That also covers a second case the offset
never handled, a file starting with blank lines and no `---`, which the
`pre-commit-config-start-empty-lines.yaml` fixture has reproduced unnoticed
since it was added: `document_start_offset` returned 0 while `end_line` was
still short by one. The offset is now unnecessary and is removed.

Edits are collected and applied rightmost-first, because replacing one scalar
shifts the columns of every scalar after it on that line, and each is checked
to have landed so a positional miss fails loudly instead of writing a
half-updated file.

The round-trip parser comes from strictyaml's vendored copy, falling back to a
standalone ruamel.yaml, so no new dependency and no reliance on strictyaml's
private attributes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.50000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.82%. Comparing base (cac24c3) to head (a8fcb40).

Files with missing lines Patch % Lines
src/sync_pre_commit_lock/pre_commit_config.py 87.50% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #79      +/-   ##
==========================================
- Coverage   97.24%   96.82%   -0.43%     
==========================================
  Files          12       12              
  Lines         727      725       -2     
  Branches       66       66              
==========================================
- Hits          707      702       -5     
- Misses         18       20       +2     
- Partials        2        3       +1     
Flag Coverage Δ
unittests 96.82% <87.50%> (-0.43%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RuntimeError: No changes to write, this should not happen

1 participant