summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--pylint/checkers/spelling.py24
-rw-r--r--tests/checkers/unittest_spelling.py72
3 files changed, 72 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index feef5dcc2..c6e3068f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -67,6 +67,14 @@ Release date: Undefined
* Don't show ``DuplicateBasesError`` for attribute access
+* Allow code flanked in backticks to be skipped by spellchecker
+
+ Closes #4319
+
+* Allow Python tool directives (for black, flake8, zimports, isort, mypy, bandit, pycharm) at beginning of comments to be skipped by spellchecker
+
+ Closes #4320
+
What's New in Pylint 2.7.4?
===========================
@@ -302,7 +310,7 @@ Release date: 2021-02-21
Close #2738
-* Fix ``duplicate-code`` false positive when lines only contain whitespace and non-alphanumeric characters (e.g. parentheses, bracket, comman, etc.)
+* Fix ``duplicate-code`` false positive when lines only contain whitespace and non-alphanumeric characters (e.g. parentheses, bracket, comma, etc.)
* Improve lint message for ``singleton-comparison`` with bools
diff --git a/pylint/checkers/spelling.py b/pylint/checkers/spelling.py
index dca7da3b5..b08ec772a 100644
--- a/pylint/checkers/spelling.py
+++ b/pylint/checkers/spelling.py
@@ -103,7 +103,7 @@ class WordsWithUnderscores(Filter):
class RegExFilter(Filter):
r"""Parent class for filters using regular expressions.
- This filter skips any words the match the expression assigned to the class attribute `_pattern`
+ This filter skips any words the match the expression assigned to the class attribute ``_pattern``
"""
_pattern: Pattern[str]
@@ -176,6 +176,24 @@ class ForwardSlashChunker(Chunker):
raise StopIteration()
+CODE_FLANKED_IN_BACKTICK_REGEX = re.compile(r"(\s|^)(`{1,2})([^`]+)(\2)([^`]|$)")
+
+
+def _strip_code_flanked_in_backticks(line: str) -> str:
+ """Alter line so code flanked in backticks is ignored.
+
+ Pyenchant automatically strips backticks when parsing tokens, so this cannot be done at the individual filter level.
+
+ """
+
+ def replace_code_but_leave_surrounding_characters(match_obj) -> str:
+ return match_obj.group(1) + match_obj.group(5)
+
+ return CODE_FLANKED_IN_BACKTICK_REGEX.sub(
+ replace_code_but_leave_surrounding_characters, line
+ )
+
+
class SpellingChecker(BaseTokenChecker):
"""Check spelling in comments and docstrings"""
@@ -323,6 +341,7 @@ class SpellingChecker(BaseTokenChecker):
"noqa",
"nosec",
"isort:skip",
+ "mypy:",
):
if line.startswith(" " + iter_directive):
line = line[(len(iter_directive) + 1) :]
@@ -330,6 +349,9 @@ class SpellingChecker(BaseTokenChecker):
starts_with_comment = True
else:
starts_with_comment = False
+
+ line = _strip_code_flanked_in_backticks(line)
+
for word, word_start_at in self.tokenizer(line.strip()):
word_start_at += initial_space
lower_cased_word = word.casefold()
diff --git a/tests/checkers/unittest_spelling.py b/tests/checkers/unittest_spelling.py
index dec6b19ee..0d946bc84 100644
--- a/tests/checkers/unittest_spelling.py
+++ b/tests/checkers/unittest_spelling.py
@@ -37,7 +37,9 @@ if enchant is not None:
pass
-class TestSpellingChecker(CheckerTestCase):
+class TestSpellingChecker(
+ CheckerTestCase
+): # pylint:disable=too-many-public-methods # This is a test case class, not sure why it would be relevant to have this pylint rule enforced for test case classes
CHECKER_CLASS = spelling.SpellingChecker
skip_on_missing_package_or_dict = pytest.mark.skipif(
@@ -303,37 +305,6 @@ class TestSpellingChecker(CheckerTestCase):
):
self.checker.visit_classdef(stmt)
- # @skip_on_missing_package_or_dict
- # # @set_config(spelling_dict=spell_dict)
- # @pytest.mark.parametrize(
- # "num_files,num_jobs,num_checkers",
- # [
- # (1, 2, 1),
- # (1, 2, 2),
- # (1, 2, 3),
- # (2, 2, 1),
- # (2, 2, 2),
- # (2, 2, 3),
- # (3, 2, 1),
- # (3, 2, 2),
- # (3, 2, 3),
- # (3, 1, 1),
- # (3, 1, 2),
- # (3, 1, 3),
- # (3, 5, 1),
- # (3, 5, 2),
- # (3, 5, 3),
- # (10, 2, 1),
- # (10, 2, 2),
- # (10, 2, 3),
- # (2, 10, 1),
- # (2, 10, 2),
- # (2, 10, 3),
- # ],
- # )
- # def test_compare_workers_to_single_proc(self, num_files, num_jobs, num_checkers):
- # assert True
-
@skip_on_missing_package_or_dict
@set_config(spelling_dict=spell_dict)
@pytest.mark.parametrize(
@@ -351,6 +322,7 @@ class TestSpellingChecker(CheckerTestCase):
("noqa", ":", "flake8 / zimports directive"),
("nosec", "", "bandit directive"),
("isort", ":skip", "isort directive"),
+ ("mypy", ":", "mypy directive"),
),
)
def test_skip_tool_directives_at_beginning_of_comments_but_still_raise_error_if_directive_appears_later_in_comment( # pylint:disable=unused-argument # Having the extra description parameter allows the description to show up in the pytest output as part of the test name when running parametrized tests
@@ -373,6 +345,42 @@ class TestSpellingChecker(CheckerTestCase):
@skip_on_missing_package_or_dict
@set_config(spelling_dict=spell_dict)
+ def test_skip_code_flanked_in_double_backticks(self):
+ full_comment = "# The function ``.qsize()`` .qsize()"
+ with self.assertAddsMessages(
+ Message(
+ "wrong-spelling-in-comment",
+ line=1,
+ args=(
+ "qsize",
+ full_comment,
+ " ^^^^^",
+ self._get_msg_suggestions("qsize"),
+ ),
+ )
+ ):
+ self.checker.process_tokens(_tokenize_str(full_comment))
+
+ @skip_on_missing_package_or_dict
+ @set_config(spelling_dict=spell_dict)
+ def test_skip_code_flanked_in_single_backticks(self):
+ full_comment = "# The function `.qsize()` .qsize()"
+ with self.assertAddsMessages(
+ Message(
+ "wrong-spelling-in-comment",
+ line=1,
+ args=(
+ "qsize",
+ full_comment,
+ " ^^^^^",
+ self._get_msg_suggestions("qsize"),
+ ),
+ )
+ ):
+ self.checker.process_tokens(_tokenize_str(full_comment))
+
+ @skip_on_missing_package_or_dict
+ @set_config(spelling_dict=spell_dict)
def test_handle_words_joined_by_forward_slash(self):
stmt = astroid.extract_node(
'''