diff --git a/docs/source/user/violations.rst b/docs/source/user/violations.rst index 8681276..e011ef0 100644 --- a/docs/source/user/violations.rst +++ b/docs/source/user/violations.rst @@ -136,6 +136,13 @@ the errors in that file will show up without having to modify our configuration. Both exist so we can choose which is better for us. +Ignoring Specific Errors within a File +-------------------------------------- + +.. code-block:: python + + # flake8: noqa E221,E222 + Selecting Violations with Flake8 ================================ diff --git a/src/flake8/checker.py b/src/flake8/checker.py index 5482454..bd1eae8 100644 --- a/src/flake8/checker.py +++ b/src/flake8/checker.py @@ -1,5 +1,6 @@ """Checker Manager and Checker classes.""" import collections +import copy import errno import itertools import logging @@ -368,7 +369,7 @@ class FileChecker(object): :type options: argparse.Namespace """ - self.options = options + self.options = copy.copy(options) self.filename = filename self.checks = checks # fmt: off @@ -384,7 +385,13 @@ class FileChecker(object): self.should_process = False if self.processor is not None: self.display_name = self.processor.filename - self.should_process = not self.processor.should_ignore_file() + should_ignore = self.processor.should_ignore_file() + if isinstance(should_ignore, list): + self.options.ignore += should_ignore + self.should_process = True + else: + self.should_process = not should_ignore + self.statistics["physical lines"] = len(self.processor.lines) def __repr__(self): # type: () -> str diff --git a/src/flake8/defaults.py b/src/flake8/defaults.py index 72452a7..d5f0cdd 100644 --- a/src/flake8/defaults.py +++ b/src/flake8/defaults.py @@ -40,4 +40,5 @@ NOQA_INLINE_REGEXP = re.compile( re.IGNORECASE, ) -NOQA_FILE = re.compile(r"\s*# flake8[:=]\s*noqa", re.I) +NOQA_FILE = re.compile( + r"\s*# flake8[:=]\s*noqa(?P\s*([A-Z]+[0-9]+(?:[,\s]+)?)+)?", re.I) diff --git a/src/flake8/processor.py b/src/flake8/processor.py index aa7f1d8..a43c790 100644 --- a/src/flake8/processor.py +++ b/src/flake8/processor.py @@ -338,18 +338,26 @@ class FileProcessor(object): def should_ignore_file(self): # type: () -> bool - """Check if ``flake8: noqa`` is in the file to be ignored. + """Check if ``flake8: noqa [Codes]`` is in the file to be ignored. :returns: True if a line matches :attr:`defaults.NOQA_FILE`, + or a list of codes to ignore if specified, otherwise False :rtype: bool """ - if not self.options.disable_noqa and any( - defaults.NOQA_FILE.match(line) for line in self.lines - ): - return True + if not self.options.disable_noqa: + found_flake_noqa_line = False + ignore_codes = [] + for line in self.lines: + matchobj = defaults.NOQA_FILE.match(line) + if matchobj: + found_flake_noqa_line = True + codes = matchobj.groupdict(default="")["codes"].split(",") + codes = (code.strip() for code in codes) + ignore_codes.extend(code for code in codes if code) + return ignore_codes or found_flake_noqa_line elif any(defaults.NOQA_FILE.search(line) for line in self.lines): LOG.warning( "Detected `flake8: noqa` on line with code. To ignore an " diff --git a/tests/unit/test_file_processor.py b/tests/unit/test_file_processor.py index e5367a8..5229276 100644 --- a/tests/unit/test_file_processor.py +++ b/tests/unit/test_file_processor.py @@ -61,6 +61,8 @@ def test_strip_utf_bom(first_line, default_options): (['\xEF\xBB\xBF"""Module docstring."""\n'], False), ([u'\uFEFF"""Module docstring."""\n'], False), (['#!/usr/bin/python', '# flake8 is great', 'a = 1'], False), + (['#!/usr/bin/python', '# flake8: noqa E221'], ["E221"]), + (['#!/usr/bin/python', '# flake8: noqa E220,E221'], ["E220", "E221"]), (['#!/usr/bin/python', '# flake8: noqa', 'a = 1'], True), (['#!/usr/bin/python', '# flake8:noqa', 'a = 1'], True), (['# flake8: noqa', '#!/usr/bin/python', 'a = 1'], True), @@ -73,14 +75,24 @@ def test_strip_utf_bom(first_line, default_options): def test_should_ignore_file(lines, expected, default_options): """Verify that we ignore a file if told to.""" file_processor = processor.FileProcessor('-', default_options, lines) - assert file_processor.should_ignore_file() is expected + assert file_processor.should_ignore_file() == expected def test_should_ignore_file_to_handle_disable_noqa(default_options): """Verify that we ignore a file if told to.""" lines = ['# flake8: noqa'] file_processor = processor.FileProcessor('-', default_options, lines) - assert file_processor.should_ignore_file() is True + assert file_processor.should_ignore_file() + default_options.disable_noqa = True + file_processor = processor.FileProcessor('-', default_options, lines) + assert file_processor.should_ignore_file() is False + + +def test_should_ignore_file_to_handle_disable_noqa_opts(default_options): + """Verify that we ignore a file if told to.""" + lines = ['# flake8: noqa E220,E221'] + file_processor = processor.FileProcessor('-', default_options, lines) + assert file_processor.should_ignore_file() == ["E220", "E221"] default_options.disable_noqa = True file_processor = processor.FileProcessor('-', default_options, lines) assert file_processor.should_ignore_file() is False