2
2
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
3
3
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
4
4
5
+ from __future__ import annotations
6
+
7
+ import os
8
+ import os .path
5
9
from pathlib import Path
6
10
11
+ import pytest
12
+ from pytest import CaptureFixture
13
+
14
+ from pylint .lint import Run as LintRun
7
15
from pylint .testutils ._run import _Run as Run
8
16
9
17
@@ -21,3 +29,131 @@ def test_fall_back_on_base_config(tmp_path: Path) -> None:
21
29
f .write ("1" )
22
30
Run ([str (test_file )], exit = False )
23
31
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]\n notes=LEVEL1,ALL_LEVELS"
51
+ conf2 = "[MISCELLANEOUS]\n notes=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]\n notes=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