Skip to content

Commit bf16c00

Browse files
Add the files option (#7496)
* Add the ``files`` option * [tests] Cover ``files`` option via the config testing framework Replace the single unit test for the new ``files`` option with functional configuration files (TOML + INI) and focused tests that use ``run_using_a_configuration_file``. Extend the helper with a ``file_to_lint=None`` mode so a config can supply files via the ``files`` option itself without positional args forcing an override. --------- Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent de4ea64 commit bf16c00

8 files changed

Lines changed: 95 additions & 18 deletions

File tree

doc/whatsnew/fragments/5701.other

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
You can now set the ``files`` option in configuration files and on the command line.
2+
Passing files without the ``--files`` flag is still supported. This allows to set
3+
``files`` to ``files = my_source_directory`` and invoking ``pylint`` with only
4+
the ``pylint`` command similar to how other CLI tools allow to do so.
5+
The help message can always be invoked with ``pylint -h`` or ``pylint --help``.
6+
7+
Closes #5701

pylint/config/config_initialization.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def _config_initialization( # pylint: disable=too-many-statements
3030
reporter: reporters.BaseReporter | reporters.MultiReporter | None = None,
3131
config_file: None | str | Path = None,
3232
verbose_mode: bool = False,
33-
) -> list[str]:
33+
) -> None:
3434
"""Parse all available options, read config files and command line arguments and
3535
set options accordingly.
3636
"""
@@ -153,17 +153,20 @@ def _config_initialization( # pylint: disable=too-many-statements
153153
linter._directory_namespaces[Path().resolve()] = (linter.config, {})
154154

155155
# parsed_args_list should now only be a list of inputs to lint.
156-
# All other options have been removed from the list.
157-
return list(
158-
chain.from_iterable(
159-
# NOTE: 'or [arg]' is needed in the case the input file or directory does
160-
# not exist and 'glob(arg)' cannot find anything. Without this we would
161-
# not be able to output the fatal import error for this module later on,
162-
# as it would get silently ignored.
163-
glob(arg, recursive=True) or [arg]
164-
for arg in parsed_args_list
156+
# All other options have been removed from the list. If there are any
157+
# positional arguments, they override any `files` set in the configuration
158+
# file.
159+
if parsed_args_list:
160+
linter.config.files = list(
161+
chain.from_iterable(
162+
# NOTE: 'or [arg]' is needed in the case the input file or directory does
163+
# not exist and 'glob(arg)' cannot find anything. Without this we would
164+
# not be able to output the fatal import error for this module later on,
165+
# as it would get silently ignored.
166+
glob(arg, recursive=True) or [arg]
167+
for arg in parsed_args_list
168+
)
165169
)
166-
)
167170

168171

169172
def _order_all_first(config_args: list[str], *, joined: bool) -> list[str]:

pylint/lint/base_options.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,18 @@ def _make_linter_options(linter: PyLinter) -> Options:
413413
"messages.",
414414
},
415415
),
416+
(
417+
"files",
418+
{
419+
"type": "csv",
420+
"default": [],
421+
"help": "The files to lint. The flag can also be omitted as pylint will "
422+
"try to lint any file passed as argument. This can be used to set files "
423+
"to a directory in a configuration file and invoke pylint by only typing "
424+
"pylint on the command line. Any file passed as argument will overwrite any "
425+
"file set in the configuration file.",
426+
},
427+
),
416428
)
417429

418430

pylint/lint/run.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def __init__(
175175
if self._is_pylint_config:
176176
_register_generate_config_options(linter._arg_parser)
177177

178-
args = _config_initialization(
178+
_config_initialization(
179179
linter, args, reporter, config_file=self._rcfile, verbose_mode=self.verbose
180180
)
181181

@@ -195,7 +195,7 @@ def __init__(
195195
disable_all_msg_set = set(
196196
msg.symbol for msg in linter.msgs_store.messages
197197
) - set(msg[1] for msg in linter.default_enabled_messages.values())
198-
if not args or (
198+
if not linter.config.files or (
199199
len(linter.config.enable) == 0
200200
and set(linter.config.disable) == disable_all_msg_set
201201
):
@@ -225,13 +225,13 @@ def __init__(
225225
try:
226226
with open(self._output, "w", encoding="utf-8") as output:
227227
linter.reporter.out = output
228-
linter.check(args)
228+
linter.check(linter.config.files)
229229
score_value = linter.generate_reports(verbose=self.verbose)
230230
except OSError as ex:
231231
print(ex, file=sys.stderr)
232232
sys.exit(32)
233233
else:
234-
linter.check(args)
234+
linter.check(linter.config.files)
235235
score_value = linter.generate_reports(verbose=self.verbose)
236236
if linter.config.clear_cache_post_run:
237237
clear_lru_caches()

pylint/testutils/configuration_test.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,18 @@ def get_expected_output(
133133

134134

135135
def run_using_a_configuration_file(
136-
configuration_path: Path | str, file_to_lint: str = __file__
136+
configuration_path: Path | str, file_to_lint: str | None = __file__
137137
) -> Run:
138-
"""Simulate a run with a configuration without really launching the checks."""
138+
"""Simulate a run with a configuration without really launching the checks.
139+
140+
Pass ``file_to_lint=None`` to omit the positional argument, e.g. when
141+
testing a configuration that supplies the files to lint via the
142+
``files`` option.
143+
"""
139144
configuration_path = str(configuration_path)
140-
args = ["--rcfile", configuration_path, file_to_lint]
145+
args = ["--rcfile", configuration_path]
146+
if file_to_lint is not None:
147+
args.append(file_to_lint)
141148
# Do not actually run checks, that could be slow. We don't mock
142149
# `PyLinter.check`: it calls `PyLinter.initialize` which is
143150
# needed to properly set up messages inclusion/exclusion
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Check that we can set the ``files`` option in an INI configuration file.
2+
# See https://github.com/pylint-dev/pylint/issues/5701
3+
[MAIN]
4+
files = src,tests/regression
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Check that we can set the ``files`` option in a TOML configuration file.
2+
# See https://github.com/pylint-dev/pylint/issues/5701
3+
4+
[tool.pylint.main]
5+
files = [
6+
"src",
7+
"tests/regression",
8+
]

tests/config/test_config.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,39 @@ def test_enable_before_disable_all_takes_effect() -> None:
242242
/ "toml_with_specific_enable_before_disable_all.toml",
243243
)
244244
assert toml_runner.linter.is_message_enabled("fixme")
245+
246+
247+
def test_files_option_parsed_from_toml() -> None:
248+
"""The ``files`` option is read from a TOML configuration file."""
249+
runner = run_using_a_configuration_file(
250+
HERE / "functional" / "toml" / "toml_with_files.toml",
251+
file_to_lint=None,
252+
)
253+
assert runner.linter.config.files == ["src", "tests/regression"]
254+
255+
256+
def test_files_option_parsed_from_ini() -> None:
257+
"""The ``files`` option is read from an INI configuration file."""
258+
runner = run_using_a_configuration_file(
259+
HERE / "functional" / "ini" / "pylintrc_with_files.ini",
260+
file_to_lint=None,
261+
)
262+
assert runner.linter.config.files == ["src", "tests/regression"]
263+
264+
265+
def test_files_option_overridden_by_positional_args() -> None:
266+
"""Positional CLI arguments override ``files`` set in a config file."""
267+
runner = run_using_a_configuration_file(
268+
HERE / "functional" / "toml" / "toml_with_files.toml",
269+
file_to_lint=str(EMPTY_MODULE),
270+
)
271+
assert runner.linter.config.files == [str(EMPTY_MODULE)]
272+
273+
274+
def test_files_option_overridden_by_files_flag() -> None:
275+
"""The ``--files`` CLI flag overrides ``files`` set in a config file."""
276+
config_path = HERE / "functional" / "toml" / "toml_with_files.toml"
277+
runner = Run(
278+
["--rcfile", str(config_path), "--files", str(EMPTY_MODULE)], exit=False
279+
)
280+
assert runner.linter.config.files == [str(EMPTY_MODULE)]

0 commit comments

Comments
 (0)