diff --git a/src/flake8/api/legacy.py b/src/flake8/api/legacy.py index 4d5c91d..8d16628 100644 --- a/src/flake8/api/legacy.py +++ b/src/flake8/api/legacy.py @@ -10,7 +10,7 @@ import logging import os.path from typing import Any -from flake8.discover_files import expand_paths +from flake8 import utils from flake8.formatting import base as formatter from flake8.main import application as app from flake8.options.parse_args import parse_args @@ -129,15 +129,12 @@ class StyleGuide: """ def excluded(path: str) -> bool: - paths = tuple( - expand_paths( - paths=[path], - stdin_display_name=self.options.stdin_display_name, - filename_patterns=self.options.filename, - exclude=self.options.exclude, - ), + return utils.matches_filename( + path, + patterns=self.options.exclude, + log_message='"%(path)s" has %(whether)sbeen excluded', + logger=LOG, ) - return not paths return excluded(filename) or ( parent is not None and excluded(os.path.join(parent, filename)) diff --git a/src/flake8/discover_files.py b/src/flake8/discover_files.py index 40b6e5c..4b3a148 100644 --- a/src/flake8/discover_files.py +++ b/src/flake8/discover_files.py @@ -22,17 +22,19 @@ def _filenames_from( :param arg: Parameter from the command-line. :param predicate: - Predicate to use to filter out filenames. If the predicate - returns ``True`` we will exclude the filename, otherwise we - will yield it. By default, we include every filename - generated. + Predicate to use to filter out paths discovered from directories + or stdin aliases. Direct file arguments are yielded even if the + predicate matches them. :returns: Generator of paths """ - if predicate(arg): + if arg == "-" and predicate(arg): return if os.path.isdir(arg): + if predicate(arg): + return + for root, sub_directories, files in os.walk(arg): # NOTE(sigmavirus24): os.walk() will skip a directory if you # remove it from the list of sub-directories. diff --git a/tests/integration/test_main.py b/tests/integration/test_main.py index 0ca5b63..b0d279d 100644 --- a/tests/integration/test_main.py +++ b/tests/integration/test_main.py @@ -135,6 +135,20 @@ def test_extend_exclude(tmpdir, capsys): assert err == "" +def test_explicit_file_ignores_exclude(tmpdir, capsys): + tmpdir.join("test/module.py").ensure() + tmpdir.join("test/module.py").write("import os\n") + tmpdir.join(".flake8").write("[flake8]\nexclude = module.py\n") + + with tmpdir.as_cwd(): + assert cli.main(["test/module.py"]) == 1 + + expected_out = "test/module.py:1:1: F401 'os' imported but unused\n" + out, err = capsys.readouterr() + assert out == expected_out.replace("/", os.sep) + assert err == "" + + def test_malformed_per_file_ignores_error(tmpdir, capsys): """Test the error message for malformed `per-file-ignores`.""" setup_cfg = """\ diff --git a/tests/unit/test_discover_files.py b/tests/unit/test_discover_files.py index ea55ccc..72293d9 100644 --- a/tests/unit/test_discover_files.py +++ b/tests/unit/test_discover_files.py @@ -95,11 +95,11 @@ def test_filenames_from_exclude_doesnt_exclude_directory_names(tmpdir): assert filenames == [os.path.join(".", "2", "1", "return_me.py")] -def test_filenames_from_predicate_applies_to_initial_arg(tmp_path): - """Test that the predicate is also applied to the passed argument.""" +def test_filenames_from_predicate_does_not_apply_to_initial_file(tmp_path): + """Test that the predicate is not applied to a directly passed file.""" fname = str(tmp_path.joinpath("f.py")) ret = tuple(_filenames_from(fname, predicate=lambda _: True)) - assert ret == () + assert ret == (fname,) def test_filenames_from_predicate_applies_to_dirname(tmp_path): @@ -164,3 +164,10 @@ def test_alternate_stdin_name_is_filtered(): def test_filename_included_even_if_not_matching_include(tmp_path): some_file = str(tmp_path.joinpath("some/file")) assert _expand_paths(paths=(some_file,)) == {some_file} + + +def test_filename_included_even_if_matching_exclude(tmp_path): + some_file = str(tmp_path.joinpath("some/file.py")) + assert _expand_paths(paths=(some_file,), exclude=("file.py",)) == { + some_file, + }