diff --git a/README.md b/README.md index 05f3016..1f2fe7d 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ It's a [Flake8](https://gitlab.com/pycqa/flake8) wrapper to make it cool. + [Check that all required plugins are installed](https://flakehell.readthedocs.io/commands/missed.html). + [Syntax highlighting in messages and code snippets](https://flakehell.readthedocs.io/formatters.html#colored-with-source-code). + [PyLint](https://github.com/PyCQA/pylint) integration. -+ [Remove unused noqa](https://flakehell.readthedocs.io/commands/dropqa.html). + [Powerful GitLab support](https://flakehell.readthedocs.io/formatters.html#gitlab). + Codes management: + Manage codes per plugin. diff --git a/docs/index.md b/docs/index.md index 392bbbc..fe27221 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,7 +12,6 @@ It's a [Flake8](https://gitlab.com/pycqa/flake8) wrapper to make it cool. + [Check that all required plugins are installed](https://flakehell.readthedocs.io/commands/missed.html). + [Syntax highlighting in messages and code snippets](https://flakehell.readthedocs.io/formatters.html#colored-with-source-code). + [PyLint](https://github.com/PyCQA/pylint) integration. -+ [Remove unused noqa](https://flakehell.readthedocs.io/commands/dropqa.html). + [Powerful GitLab support](https://flakehell.readthedocs.io/formatters.html#gitlab). + Codes management: + Manage codes per plugin. @@ -49,5 +48,4 @@ FlakeHell supports all flake8 plugins, formatters, and configs. However, FlakeHe commands/codes commands/code commands/missed - commands/dropqa ``` diff --git a/flakehell/_logic/__init__.py b/flakehell/_logic/__init__.py index 18e063f..db26f32 100644 --- a/flakehell/_logic/__init__.py +++ b/flakehell/_logic/__init__.py @@ -6,7 +6,6 @@ from ._extractors import extract from ._plugin import check_include, get_exceptions, get_plugin_name, get_plugin_rules from ._snapshot import Snapshot, prepare_cache -from ._yesqa import YesQA __all__ = [ diff --git a/flakehell/_logic/_yesqa.py b/flakehell/_logic/_yesqa.py deleted file mode 100644 index e083d70..0000000 --- a/flakehell/_logic/_yesqa.py +++ /dev/null @@ -1,102 +0,0 @@ -# built-in -import json -import re -from collections import defaultdict -from contextlib import redirect_stdout -from io import StringIO -from pathlib import Path -from typing import Dict, List, Set - -# app -from .._constants import NAME, VERSION - - -CODE = '[a-z]+[0-9]+' -SEP = r'[,\s]+' - - -class YesQA: - noqa_file_re = re.compile(r'^# flake8[:=]\s*noqa', re.I) - noqa_re = re.compile(f'# noqa(: ?{CODE}({SEP}{CODE})*)?', re.I) - code_re = re.compile(CODE, re.I) - - def get_ignored_codes(self, line: str) -> List[str]: - match = self.noqa_re.search(line) - if not match: - return [] - comment = match.group() - return self.code_re.findall(comment) - - def remove_noqa(self, line: str) -> str: - if self.noqa_file_re.match(line): - return '' - match = self.noqa_re.search(line) - if not match: - return line - line = line[:match.start()] + line[match.end():] - return line.rstrip() - - def remove_noqa_code(self, line: str, code: str) -> str: - match = self.noqa_re.search(line) - if not match: - return line - comment = match.group() - codes = self.code_re.findall(comment) - - # if it was only one code and we remove it, remove the comment at all - if codes == [code]: - return self.remove_noqa(line) - - # remove only one code from the list of codes - codes = [c for c in codes if c != code] - new_comment = '# noqa: ' + ', '.join(codes) - line = line[:match.start()] + new_comment + line[match.end():] - return line.rstrip() - - def get_errors(self, path: Path, noqa: bool) -> Dict[int, Set[str]]: - from .._patched import FlakeHellApplication - - app = FlakeHellApplication(program=NAME, version=VERSION) - output = StringIO() - cmd = ['--format', 'json', str(path)] - if not noqa: - cmd.append('--disable-noqa') - with redirect_stdout(output): - app.run(cmd) - output.seek(0) - - result = defaultdict(set) - for line in output: - data = json.loads(line) - result[data['line']].add(data['code']) - return dict(result) - - def remove_unused_codes(self, content: str, errors: Dict[int, Set[str]]) -> str: - result = [] - for line_number, line in enumerate(content.split('\n'), 1): - ignored_codes = self.get_ignored_codes(line) - actual_codes = errors.get(line_number, set()) - for code in ignored_codes: - if code not in actual_codes: - line = self.remove_noqa_code(line=line, code=code) - result.append(line) - return '\n'.join(result) - - def get_modified_file(self, path: Path, original: str) -> str: - old_errors = self.get_errors(path=path, noqa=True) - all_errors = self.get_errors(path=path, noqa=False) - new_errors = dict() - for line_number, codes in all_errors.items(): - new_codes = codes - old_errors.get(line_number, set()) - if new_codes: - new_errors[line_number] = new_codes - - return self.remove_unused_codes(content=original, errors=new_errors) - - def __call__(self, path: Path) -> bool: - original = path.read_text(encoding='utf-8') - modified = self.get_modified_file(path=path, original=original) - if modified == original: - return False - path.write_text(modified) - return True diff --git a/flakehell/commands/__init__.py b/flakehell/commands/__init__.py index 6ab8c9f..48bc529 100644 --- a/flakehell/commands/__init__.py +++ b/flakehell/commands/__init__.py @@ -9,7 +9,6 @@ from ._missed import missed_command from ._plugins import plugins_command from ._version import version_command -from ._dropqa import dropqa_command __all__ = [ @@ -22,7 +21,6 @@ 'missed_command', 'plugins_command', 'version_command', - 'dropqa_command', ] @@ -33,6 +31,5 @@ 'lint': lint_command, 'missed': missed_command, 'plugins': plugins_command, - 'dropqa': dropqa_command, '--version': version_command, }) diff --git a/flakehell/commands/_dropqa.py b/flakehell/commands/_dropqa.py deleted file mode 100644 index 8901f61..0000000 --- a/flakehell/commands/_dropqa.py +++ /dev/null @@ -1,37 +0,0 @@ -# built-in -from pathlib import Path - -# app -from .._constants import ExitCode -from .._logic import YesQA -from .._types import CommandResult - - -def get_paths(paths): - for path in paths: - if path.is_dir(): - yield from get_paths(path.iterdir()) - continue - if path.suffix != '.py': - continue - if not path.is_file(): - continue - yield path - - -def dropqa_command(argv) -> CommandResult: - """Remove bare and unused noqa comments. - """ - if not argv: - return ExitCode.NOT_ENOUGH_ARGS, 'no file path provided' - if argv[0] == '--help': - print(dropqa_command.__doc__) - return ExitCode.OK, '' - - paths = get_paths(Path(fname) for fname in argv) - fixer = YesQA() - for path in paths: - modified = fixer(path=path) - if modified: - print(str(path)) - return ExitCode.OK, '' diff --git a/tests/test_logic/test_yesqa.py b/tests/test_logic/test_yesqa.py deleted file mode 100644 index 3583d5c..0000000 --- a/tests/test_logic/test_yesqa.py +++ /dev/null @@ -1,56 +0,0 @@ -# built-in -from pathlib import Path -from unittest.mock import patch - -# external -import pytest - -# project -from flakehell._logic import YesQA - -# app -from ..utils import chdir - - -@patch('sys.argv', ['flakehell']) -def get_modified(content: str, path: Path) -> str: - path = path / 'tmp.py' - path.write_text(content) - with chdir(path.parent): - return YesQA().get_modified_file(path=path, original=content) - - -@patch('sys.argv', ['flakehell']) -@pytest.mark.parametrize('content', [ - 'print("hello")', - # don't add not ignored codes - 'err=1', - # don't touch other codes - 'err=1 # noqa: E225', - # preserve case - 'err=1 # NoQA: E225', - # respect tokenization structure - # 'err="# noqa: E117"', -]) -def test_not_modified(content: str, tmp_path: Path): - assert get_modified(content=content, path=tmp_path) == content - - -@patch('sys.argv', ['flakehell']) -@pytest.mark.parametrize('given, expected', [ - # remove one code - ('err=1 # noqa: E225, E117', 'err=1 # noqa: E225'), - ('err=1 # noqa: E117, E225', 'err=1 # noqa: E225'), - # don't touch text after - ('err=1 # noqa: E225, E117 # comment', 'err=1 # noqa: E225 # comment'), - # remove comment when the last code is removed - ('err=1 # noqa: E117', 'err=1'), - # case insensitive - ('err=1 # NoQA: E117', 'err=1'), - - # https://github.com/asottile/yesqa/blob/master/tests/yesqa_test.py - ('import os # noqa: F401,X999\n', 'import os # noqa: F401\n'), - ('import os # noqa:F401,X999\n', 'import os # noqa: F401\n'), -]) -def test_modified(given: str, expected: str, tmp_path: Path): - assert get_modified(content=given, path=tmp_path) == expected