Repository: codespell-project/codespell

Issue:
Add a way to ignore line endings when matching lines from `--exclude-file`
This can be especially when repository is used on Windows with git's `core.autocrlf` set to `true` as then some files can have CRLF line endings locally even though they're checked out into git with LF endings. This mixing can therefore cause `codespell` to not ignore some lines if the line endings in `--exclude-file` differ from line endings in the file with spelling issue.


Discussion:
Yeah I'd agree, the line ending should be irrelevant within any of our config files (--exclude-file, --ignore-word-list) etc.

Resolving patch:
diff --git a/codespell_lib/_codespell.py b/codespell_lib/_codespell.py
--- a/codespell_lib/_codespell.py
+++ b/codespell_lib/_codespell.py
@@ -628,7 +628,7 @@ def parse_ignore_words_option(ignore_words_option: List[str]) -> Set[str]:
 def build_exclude_hashes(filename: str, exclude_lines: Set[str]) -> None:
     with open(filename, encoding="utf-8") as f:
         for line in f:
-            exclude_lines.add(line)
+            exclude_lines.add(line.rstrip())
 
 
 def build_ignore_words(filename: str, ignore_words: Set[str]) -> None:
@@ -896,7 +896,7 @@ def parse_file(
             return bad_count
 
     for i, line in enumerate(lines):
-        if line in exclude_lines:
+        if line.rstrip() in exclude_lines:
             continue
 
         fixed_words = set()


Test patch:
diff --git a/codespell_lib/tests/test_basic.py b/codespell_lib/tests/test_basic.py
--- a/codespell_lib/tests/test_basic.py
+++ b/codespell_lib/tests/test_basic.py
@@ -325,10 +325,21 @@ def test_ignore_dictionary(
 ) -> None:
     """Test ignore dictionary functionality."""
     bad_name = tmp_path / "bad.txt"
-    bad_name.write_text("1 abandonned 1\n2 abandonned 2\nabondon\n")
-    assert cs.main(bad_name) == 3
+    bad_name.write_text(
+        "1 abandonned 1\n"
+        "2 abandonned 2\n"
+        "3 abandonned 3\r\n"
+        "4 abilty 4\n"
+        "5 abilty 5\n"
+        "6 abilty 6\r\n"
+        "7 ackward 7\n"
+        "8 ackward 8\n"
+        "9 ackward 9\r\n"
+        "abondon\n"
+    )
+    assert cs.main(bad_name) == 10
     fname = tmp_path / "ignore.txt"
-    fname.write_text("abandonned\n")
+    fname.write_text("abandonned\nabilty\r\nackward")
     assert cs.main("-I", fname, bad_name) == 1
 
 
@@ -363,11 +374,27 @@ def test_exclude_file(
 ) -> None:
     """Test exclude file functionality."""
     bad_name = tmp_path / "bad.txt"
-    bad_name.write_bytes(b"1 abandonned 1\n2 abandonned 2\n")
-    assert cs.main(bad_name) == 2
+    # check all possible combinations of lines to ignore and ignores
+    combinations = "".join(
+        f"{n} abandonned {n}\n"
+        f"{n} abandonned {n}\r\n"
+        f"{n} abandonned {n} \n"
+        f"{n} abandonned {n} \r\n"
+        for n in range(1, 5)
+    )
+    bad_name.write_bytes(
+        (combinations + "5 abandonned 5\n6 abandonned 6").encode("utf-8")
+    )
+    assert cs.main(bad_name) == 18
     fname = tmp_path / "tmp.txt"
-    fname.write_bytes(b"1 abandonned 1\n")
-    assert cs.main(bad_name) == 2
+    fname.write_bytes(
+        b"1 abandonned 1\n"
+        b"2 abandonned 2\r\n"
+        b"3 abandonned 3 \n"
+        b"4 abandonned 4 \r\n"
+        b"6 abandonned 6\n"
+    )
+    assert cs.main(bad_name) == 18
     assert cs.main("-x", fname, bad_name) == 1