Skip to content

Commit 3dfa14f

Browse files
[spelling] Ignore spelling in type/mypy type ignore comments (#8370) (#8373)
enchant does not understand class name well enough so it creates false positives, and mypy type ignore comments with additional text are a syntax error anyway, so raising a spelling mistakes for it is not really important. (cherry picked from commit b5aab35) Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 71cdb25 commit 3dfa14f

File tree

3 files changed

+28
-37
lines changed

3 files changed

+28
-37
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix false positive for ``wrong-spelling-in-comment`` with class names in a python 2 type comment.
2+
3+
Closes #8370

pylint/checkers/spelling.py

+4-19
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ def _next(self) -> tuple[str, Literal[0]]:
172172

173173

174174
CODE_FLANKED_IN_BACKTICK_REGEX = re.compile(r"(\s|^)(`{1,2})([^`]+)(\2)([^`]|$)")
175-
MYPY_IGNORE_DIRECTIVE_RULE_REGEX = re.compile(r"(\s|^)(type\: ignore\[[^\]]+\])(.*)")
176175

177176

178177
def _strip_code_flanked_in_backticks(line: str) -> str:
@@ -190,23 +189,6 @@ def replace_code_but_leave_surrounding_characters(match_obj: re.Match[str]) -> s
190189
)
191190

192191

193-
def _strip_mypy_ignore_directive_rule(line: str) -> str:
194-
"""Alter line so mypy rule name is ignored.
195-
196-
Pyenchant parses anything flanked by spaces as an individual token,
197-
so this cannot be done at the individual filter level.
198-
"""
199-
200-
def replace_rule_name_but_leave_surrounding_characters(
201-
match_obj: re.Match[str],
202-
) -> str:
203-
return match_obj.group(1) + match_obj.group(3)
204-
205-
return MYPY_IGNORE_DIRECTIVE_RULE_REGEX.sub(
206-
replace_rule_name_but_leave_surrounding_characters, line
207-
)
208-
209-
210192
class SpellingChecker(BaseTokenChecker):
211193
"""Check spelling in comments and docstrings."""
212194

@@ -362,7 +344,6 @@ def _check_spelling(self, msgid: str, line: str, line_num: int) -> None:
362344
starts_with_comment = False
363345

364346
line = _strip_code_flanked_in_backticks(line)
365-
line = _strip_mypy_ignore_directive_rule(line)
366347

367348
for word, word_start_at in self.tokenizer(line.strip()):
368349
word_start_at += initial_space
@@ -436,6 +417,10 @@ def process_tokens(self, tokens: list[tokenize.TokenInfo]) -> None:
436417
if token.startswith("# pylint:"):
437418
# Skip pylint enable/disable comments
438419
continue
420+
if token.startswith("# type: "):
421+
# Skip python 2 type comments and mypy type ignore comments
422+
# mypy do not support additional text in type comments
423+
continue
439424
self._check_spelling("wrong-spelling-in-comment", token, start_row)
440425

441426
@only_required_for_messages("wrong-spelling-in-docstring")

tests/checkers/unittest_spelling.py

+21-18
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,27 @@ def test_skip_urls(self) -> None:
243243
self.checker.process_tokens(_tokenize_str("# https://github.com/rfk/pyenchant"))
244244
assert not self.linter.release_messages()
245245

246+
@skip_on_missing_package_or_dict
247+
@set_config(spelling_dict=spell_dict)
248+
@pytest.mark.parametrize(
249+
"type_comment",
250+
[
251+
"# type: (NotAWord) -> NotAWord",
252+
"# type: List[NotAWord] -> List[NotAWord]",
253+
"# type: Dict[NotAWord] -> Dict[NotAWord]",
254+
"# type: NotAWord",
255+
"# type: List[NotAWord]",
256+
"# type: Dict[NotAWord]",
257+
"# type: ImmutableList[Manager]",
258+
# will result in error: Invalid "type: ignore" comment [syntax]
259+
# when analyzed with mypy 1.02
260+
"# type: ignore[attr-defined] NotAWord",
261+
],
262+
)
263+
def test_skip_type_comments(self, type_comment: str) -> None:
264+
self.checker.process_tokens(_tokenize_str(type_comment))
265+
assert not self.linter.release_messages()
266+
246267
@skip_on_missing_package_or_dict
247268
@set_config(spelling_dict=spell_dict)
248269
def test_skip_sphinx_directives(self) -> None:
@@ -348,24 +369,6 @@ def test_skip_code_flanked_in_single_backticks(self) -> None:
348369
):
349370
self.checker.process_tokens(_tokenize_str(full_comment))
350371

351-
@skip_on_missing_package_or_dict
352-
@set_config(spelling_dict=spell_dict)
353-
def test_skip_mypy_ignore_directives(self) -> None:
354-
full_comment = "# type: ignore[attr-defined] attr"
355-
with self.assertAddsMessages(
356-
MessageTest(
357-
"wrong-spelling-in-comment",
358-
line=1,
359-
args=(
360-
"attr",
361-
full_comment,
362-
" ^^^^",
363-
self._get_msg_suggestions("attr"),
364-
),
365-
)
366-
):
367-
self.checker.process_tokens(_tokenize_str(full_comment))
368-
369372
@skip_on_missing_package_or_dict
370373
@set_config(
371374
spelling_dict=spell_dict,

0 commit comments

Comments
 (0)