Skip to content

Commit 266c0fa

Browse files
author
Aleksey Petryankin
committed
Add tests for different configs in different directories
1 parent d603f94 commit 266c0fa

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

tests/config/test_per_directory_config.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
33
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
44

5+
from __future__ import annotations
6+
7+
import os
8+
import os.path
59
from pathlib import Path
610

11+
import pytest
12+
from pytest import CaptureFixture
13+
14+
from pylint.lint import Run as LintRun
715
from pylint.testutils._run import _Run as Run
816

917

@@ -21,3 +29,131 @@ def test_fall_back_on_base_config(tmp_path: Path) -> None:
2129
f.write("1")
2230
Run([str(test_file)], exit=False)
2331
assert id(runner.linter.config) == id(runner.linter._base_config)
32+
33+
34+
@pytest.fixture
35+
def _create_subconfig_test_fs(tmp_path: Path) -> tuple[Path, Path, Path]:
36+
level1_dir = tmp_path / "level1_dir"
37+
level1_init = level1_dir / "__init__.py"
38+
conf_file1 = level1_dir / "pylintrc"
39+
test_file1 = level1_dir / "a.py"
40+
subdir = level1_dir / "sub"
41+
level2_init = subdir / "__init__.py"
42+
conf_file2 = subdir / "pylintrc"
43+
test_file2 = subdir / "b.py"
44+
os.makedirs(subdir)
45+
level1_init.touch()
46+
level2_init.touch()
47+
test_file_text = "#LEVEL1\n#LEVEL2\n#ALL_LEVELS\n#TODO\n"
48+
test_file1.write_text(test_file_text)
49+
test_file2.write_text(test_file_text)
50+
conf1 = "[MISCELLANEOUS]\nnotes=LEVEL1,ALL_LEVELS"
51+
conf2 = "[MISCELLANEOUS]\nnotes=LEVEL2,ALL_LEVELS"
52+
conf_file1.write_text(conf1)
53+
conf_file2.write_text(conf2)
54+
return level1_dir, test_file1, test_file2
55+
56+
57+
# check that use-parent-configs doesn't break anything
58+
@pytest.mark.parametrize(
59+
"local_config_args",
60+
[["--use-local-configs=y"], ["--use-local-configs=y", "--use-parent-configs=y"]],
61+
)
62+
# check files and configs from top-level package or subpackage
63+
@pytest.mark.parametrize("test_file_index", [0, 1])
64+
# check cases when cwd contains pylintrc or not
65+
@pytest.mark.parametrize("start_dir_modificator", [".", ".."])
66+
def test_subconfig_vs_root_config(
67+
_create_subconfig_test_fs: tuple[Path, Path, Path],
68+
capsys: CaptureFixture,
69+
test_file_index: int,
70+
local_config_args: list[str],
71+
start_dir_modificator: str,
72+
) -> None:
73+
"""Test that each checked file or module uses config
74+
from its own directory.
75+
"""
76+
level1_dir, *tmp_files = _create_subconfig_test_fs
77+
test_file = tmp_files[test_file_index]
78+
start_dir = (level1_dir / start_dir_modificator).resolve()
79+
80+
orig_cwd = os.getcwd()
81+
output = [f"{start_dir = }, {test_file = }"]
82+
os.chdir(start_dir)
83+
for _ in range(2):
84+
# _Run adds --rcfile, which overrides config from cwd, so we need original Run here
85+
LintRun([*local_config_args, str(test_file)], exit=False)
86+
output.append(capsys.readouterr().out.replace("\\n", "\n"))
87+
88+
test_file = test_file.parent
89+
os.chdir(orig_cwd)
90+
91+
expected_note = f"LEVEL{test_file_index+1}"
92+
assert (
93+
expected_note in output[1]
94+
), f"readable debug output:\n{output[0]}\n{output[1]}"
95+
assert (
96+
expected_note in output[2]
97+
), f"readable debug output:\n{output[0]}\n{output[2]}"
98+
if test_file_index == 0:
99+
# 'pylint level1_dir/' should use config from subpackage when checking level1_dir/sub/b.py
100+
assert (
101+
"LEVEL2" in output[2]
102+
), f"readable debug output:\n{output[0]}\n{output[2]}"
103+
else:
104+
# 'pylint level1_dir/sub/b.py' and 'pylint level1_dir/sub/' should use
105+
# level1_dir/sub/pylintrc, not level1_dir/pylintrc
106+
assert (
107+
"LEVEL1" not in output[1]
108+
), f"readable debug output:\n{output[0]}\n{output[1]}"
109+
assert (
110+
"LEVEL1" not in output[2]
111+
), f"readable debug output:\n{output[0]}\n{output[2]}"
112+
113+
114+
@pytest.mark.parametrize("test_file_index", [0, 1])
115+
def test_subconfig_vs_cli_arg(
116+
_create_subconfig_test_fs: tuple[Path, Path, Path],
117+
capsys: CaptureFixture,
118+
test_file_index: int,
119+
) -> None:
120+
"""Test that cli args have priority over subconfigs."""
121+
test_root, *tmp_files = _create_subconfig_test_fs
122+
test_file = tmp_files[test_file_index]
123+
orig_cwd = os.getcwd()
124+
os.chdir(test_root)
125+
Run(["--notes=FIXME", "--use-local-configs=y", str(test_file)], exit=False)
126+
output = capsys.readouterr().out.replace("\\n", "\n")
127+
os.chdir(orig_cwd)
128+
129+
# check that cli arg overrides default value
130+
assert "TODO" not in output
131+
# notes=FIXME in cli should override all pylintrc configs
132+
assert "ALL_LEVELS" not in output
133+
134+
135+
def _create_parent_subconfig_fs(tmp_path: Path) -> Path:
136+
level1_dir = tmp_path / "package"
137+
conf_file = level1_dir / "pylintrc"
138+
subdir = level1_dir / "sub"
139+
test_file = subdir / "b.py"
140+
os.makedirs(subdir)
141+
test_file_text = "#LEVEL1\n#LEVEL2\n#TODO\n"
142+
test_file.write_text(test_file_text)
143+
conf = "[MISCELLANEOUS]\nnotes=LEVEL1,LEVEL2"
144+
conf_file.write_text(conf)
145+
return test_file
146+
147+
148+
def test_subconfig_in_parent(tmp_path: Path, capsys: CaptureFixture) -> None:
149+
"""Test that searching local configs in parent directories works."""
150+
test_file = _create_parent_subconfig_fs(tmp_path)
151+
orig_cwd = os.getcwd()
152+
os.chdir(tmp_path)
153+
Run(["--use-parent-configs=y", "--use-local-configs=y", str(test_file)], exit=False)
154+
output1 = capsys.readouterr().out.replace("\\n", "\n")
155+
os.chdir(orig_cwd)
156+
157+
# check that file is linted with config from ../, which is not a cwd
158+
assert "TODO" not in output1
159+
assert "LEVEL1" in output1

0 commit comments

Comments
 (0)