Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect ignore configuration options when --recursive=y. #6528

Merged
merged 18 commits into from May 13, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -308,6 +308,10 @@ What's New in Pylint 2.13.9?
Release date: TBA


* Respect ignore configuration options when ``--recursive=y``.
matusvalo marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -864,6 +864,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 @@ -1228,17 +1228,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"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘

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(
matusvalo marked this conversation as resolved.
Show resolved Hide resolved
[
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 @@ -1249,7 +1323,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