Skip to content

Do not report a fix that --ignore-regex made impossible - #3994

Open
Eljees wants to merge 1 commit into
codespell-project:mainfrom
Eljees:fix-ignore-regex-write-changes
Open

Do not report a fix that --ignore-regex made impossible#3994
Eljees wants to merge 1 commit into
codespell-project:mainfrom
Eljees:fix-ignore-regex-write-changes

Conversation

@Eljees

@Eljees Eljees commented Aug 14, 2026

Copy link
Copy Markdown

Fixes #2056.

What happens

$ printf '1nd\n1nd_2nd\n' > test.txt
$ codespell test.txt --ignore-regex _ --write-changes
FIXED: test.txt
  test.txt:1: 1nd ==> 1st
  test.txt:2: 1nd ==> 1st
$ echo $?
0
$ cat test.txt
1st
1nd_2nd

Line 2 is reported as fixed, is not fixed, and does not affect the exit code — so a CI run goes green with the misspelling still in the file, and running codespell again prints the same false FIXED: forever.

Why

Detection and writing look at two different texts. Detection walks the line with --ignore-regex substituted out (_ignore_word_sub replaces the match with a space), so it sees 1nd 2nd and finds 1nd. --write-changes then substitutes on the original line:

if options.write_changes and fix:
    changed = True
    lines[i] = re.sub(rf"\b{word}\b", fixword, lines[i])
    fixed_words.add(word)
    changes_made.append((line_number + 1, word, fixword))
    continue

In 1nd_2nd there is no word boundary between 1nd and _, so re.sub matches nothing. But changed is set before the result is inspected, changes_made records a change that never happened, and continue skips the warning branch that would have set the exit code.

The change

Keep the result of the substitution, and only claim the fix when the line really changed; otherwise fall through to the normal warning. --ignore-regex semantics are untouched — the word is still detected, it is just reported instead of silently dropped. This is the second of the two outcomes the reporter said would be acceptable ("either fix it, or tell me it can't").

After:

FIXED: test.txt
  test.txt:1: 1nd ==> 1st
test.txt:2: 1nd ==> 1st
$ echo $?
65

Tests

test_ignore_regex_with_write_changes in codespell_lib/tests/test_basic.py, next to the existing --ignore-regex tests. It asserts all three symptoms: line 1 is rewritten, line 2 is not listed as fixed, and the exit code is non-zero. On main it fails on the middle assertion.

pytest codespell_lib/tests/test_basic.py: 85 passed on main, 86 passed with this change, no failures either way. ruff check, ruff format --check and mypy are clean (mypy reports the same two pre-existing chardet stub errors on an untouched tree).

Detection runs on the text with --ignore-regex substituted out, while
--write-changes substitutes on the original line.  A word that only
exists in the substituted text (1nd in 1nd_2nd, with --ignore-regex _)
therefore matches nothing: the line is left untouched, but codespell
still prints FIXED, still lists the change, and still exits 0.

Keep the result of the substitution and only claim the fix when the
line actually changed; otherwise fall through to the normal warning,
which also restores the exit code.

Fixes codespell-project#2056
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.

--ignore-regex does not work with --write-changes

1 participant