Skip to content

Commit

Permalink
Respect ignore configuration options when --recursive=y. (#6528)
Browse files Browse the repository at this point in the history
* Ignore specified files/directories in recursive mode

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update Changelog

* Fix typo in Changelog

* Fix typo in comment

* Add missing regrtest data directory

* Improved unittests

* Move common code of checking if file is ignored to separate function

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Rename is_ignored_file to _is_ignored_file

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update ChangeLog

Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
  • Loading branch information
4 people committed May 13, 2022
1 parent dc18f82 commit 6ad350f
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 8 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -325,6 +325,10 @@ What's New in Pylint 2.13.9?
Release date: TBA


* Respect ignore configuration options with ``--recursive=y``.

Closes #6471

* Fix false positives for ``no-name-in-module`` and ``import-error`` for ``numpy.distutils`` and ``pydantic``.

Closes #6497
Expand Down
20 changes: 16 additions & 4 deletions pylint/lint/expand_modules.py
Expand Up @@ -46,6 +46,20 @@ def _is_in_ignore_list_re(element: str, ignore_list_re: list[Pattern[str]]) -> b
return any(file_pattern.match(element) for file_pattern in ignore_list_re)


def _is_ignored_file(
element: str,
ignore_list: list[str],
ignore_list_re: list[Pattern[str]],
ignore_list_paths_re: list[Pattern[str]],
) -> bool:
basename = os.path.basename(element)
return (
basename in ignore_list
or _is_in_ignore_list_re(basename, ignore_list_re)
or _is_in_ignore_list_re(element, ignore_list_paths_re)
)


def expand_modules(
files_or_modules: Sequence[str],
ignore_list: list[str],
Expand All @@ -61,10 +75,8 @@ def expand_modules(

for something in files_or_modules:
basename = os.path.basename(something)
if (
basename in ignore_list
or _is_in_ignore_list_re(os.path.basename(something), ignore_list_re)
or _is_in_ignore_list_re(something, ignore_list_paths_re)
if _is_ignored_file(
something, ignore_list, ignore_list_re, ignore_list_paths_re
):
continue
module_path = get_python_path(something)
Expand Down
15 changes: 12 additions & 3 deletions pylint/lint/pylinter.py
Expand Up @@ -31,7 +31,7 @@
)
from pylint.lint.base_options import _make_linter_options
from pylint.lint.caching import load_results, save_results
from pylint.lint.expand_modules import expand_modules
from pylint.lint.expand_modules import _is_ignored_file, expand_modules
from pylint.lint.message_state_handler import _MessageStateHandler
from pylint.lint.parallel import check_parallel
from pylint.lint.report_functions import (
Expand Down Expand Up @@ -564,8 +564,7 @@ def initialize(self) -> None:
if not msg.may_be_emitted():
self._msgs_state[msg.msgid] = False

@staticmethod
def _discover_files(files_or_modules: Sequence[str]) -> Iterator[str]:
def _discover_files(self, files_or_modules: Sequence[str]) -> Iterator[str]:
"""Discover python modules and packages in sub-directory.
Returns iterator of paths to discovered modules and packages.
Expand All @@ -579,6 +578,16 @@ def _discover_files(files_or_modules: Sequence[str]) -> Iterator[str]:
if any(root.startswith(s) for s in skip_subtrees):
# Skip subtree of already discovered package.
continue

if _is_ignored_file(
root,
self.config.ignore,
self.config.ignore_patterns,
self.config.ignore_paths,
):
skip_subtrees.append(root)
continue

if "__init__.py" in files:
skip_subtrees.append(root)
yield root
Expand Down
43 changes: 43 additions & 0 deletions tests/lint/unittest_lint.py
Expand Up @@ -869,6 +869,49 @@ def test_by_module_statement_value(initialized_linter: PyLinter) -> None:
assert module_stats["statement"] == linter2.stats.statement


@pytest.mark.parametrize(
"ignore_parameter,ignore_parameter_value",
[
("--ignore", "failing.py"),
("--ignore", "ignored_subdirectory"),
("--ignore-patterns", "failing.*"),
("--ignore-patterns", "ignored_*"),
("--ignore-paths", ".*directory/ignored.*"),
("--ignore-paths", ".*ignored.*/failing.*"),
],
)
def test_recursive_ignore(ignore_parameter, ignore_parameter_value) -> None:
run = Run(
[
"--recursive",
"y",
ignore_parameter,
ignore_parameter_value,
join(REGRTEST_DATA_DIR, "directory"),
],
exit=False,
)

linted_files = run.linter._iterate_file_descrs(
tuple(run.linter._discover_files([join(REGRTEST_DATA_DIR, "directory")]))
)
linted_file_paths = [file_item.filepath for file_item in linted_files]

ignored_file = os.path.abspath(
join(REGRTEST_DATA_DIR, "directory", "ignored_subdirectory", "failing.py")
)
assert ignored_file not in linted_file_paths

for regrtest_data_module in (
("directory", "subdirectory", "subsubdirectory", "module.py"),
("directory", "subdirectory", "module.py"),
("directory", "package", "module.py"),
("directory", "package", "subpackage", "module.py"),
):
module = os.path.abspath(join(REGRTEST_DATA_DIR, *regrtest_data_module))
assert module in linted_file_paths


def test_import_sibling_module_from_namespace(initialized_linter: PyLinter) -> None:
"""If the parent directory above `namespace` is on sys.path, ensure that
modules under `namespace` can import each other without raising `import-error`."""
Expand Down
@@ -0,0 +1 @@
import re
76 changes: 75 additions & 1 deletion tests/test_self.py
Expand Up @@ -1229,17 +1229,91 @@ def test_max_inferred_for_complicated_class_hierarchy() -> None:
assert not ex.value.code % 2

def test_regression_recursive(self):
"""Tests if error is raised when linter is executed over directory not using --recursive=y"""
self._test_output(
[join(HERE, "regrtest_data", "directory", "subdirectory"), "--recursive=n"],
expected_output="No such file or directory",
)

def test_recursive(self):
"""Tests if running linter over directory using --recursive=y"""
self._runtest(
[join(HERE, "regrtest_data", "directory", "subdirectory"), "--recursive=y"],
code=0,
)

def test_ignore_recursive(self):
"""Tests recursive run of linter ignoring directory using --ignore parameter.
Ignored directory contains files yielding lint errors. If directory is not ignored
test would fail due these errors.
"""
self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore=ignored_subdirectory",
],
code=0,
)

self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore=failing.py",
],
code=0,
)

def test_ignore_pattern_recursive(self):
"""Tests recursive run of linter ignoring directory using --ignore-parameter parameter.
Ignored directory contains files yielding lint errors. If directory is not ignored
test would fail due these errors.
"""
self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore-pattern=ignored_.*",
],
code=0,
)

self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore-pattern=failing.*",
],
code=0,
)

def test_ignore_path_recursive(self):
"""Tests recursive run of linter ignoring directory using --ignore-path parameter.
Ignored directory contains files yielding lint errors. If directory is not ignored
test would fail due these errors.
"""
self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore-path=.*ignored.*",
],
code=0,
)

self._runtest(
[
join(HERE, "regrtest_data", "directory"),
"--recursive=y",
"--ignore-path=.*failing.*",
],
code=0,
)

def test_recursive_current_dir(self):
with _test_sys_path():
# pytest is including directory HERE/regrtest_data to sys.path which causes
Expand All @@ -1250,7 +1324,7 @@ def test_recursive_current_dir(self):
if not os.path.basename(path) == "regrtest_data"
]
with _test_cwd():
os.chdir(join(HERE, "regrtest_data", "directory"))
os.chdir(join(HERE, "regrtest_data", "directory", "subdirectory"))
self._runtest(
[".", "--recursive=y"],
code=0,
Expand Down

0 comments on commit 6ad350f

Please sign in to comment.