diff --git a/custom_dict.txt b/custom_dict.txt index 3bac1945fd..c4809615f3 100644 --- a/custom_dict.txt +++ b/custom_dict.txt @@ -191,6 +191,7 @@ lineset's linesets linkers linter +linter's linux listcomp Logilab @@ -228,6 +229,7 @@ mymodule mypy namedtuple namespace +natively newsfile newstyle nl diff --git a/doc/whatsnew/fragments/8460.bugfix b/doc/whatsnew/fragments/8460.bugfix new file mode 100644 index 0000000000..b14bf18e00 --- /dev/null +++ b/doc/whatsnew/fragments/8460.bugfix @@ -0,0 +1,3 @@ +Fix ``store_true`` boolean config options (like ``exit-zero``) in TOML files not respecting ``false`` values. Setting ``exit-zero = false`` in a TOML config previously behaved the same as ``exit-zero = true``. + +Closes #8460 diff --git a/pylint/config/config_file_parser.py b/pylint/config/config_file_parser.py index 4ceed28d6e..513cd5dd50 100644 --- a/pylint/config/config_file_parser.py +++ b/pylint/config/config_file_parser.py @@ -6,6 +6,7 @@ from __future__ import annotations +import argparse import configparser import os import sys @@ -60,7 +61,9 @@ def _ini_file_with_sections(file_path: Path) -> bool: return False @staticmethod - def parse_toml_file(file_path: Path) -> PylintConfigFileData: + def parse_toml_file( + file_path: Path, store_true_options: set[str] | None = None + ) -> PylintConfigFileData: """Parse and handle errors of a toml configuration file. Raises ``tomllib.TOMLDecodeError``. @@ -77,18 +80,38 @@ def parse_toml_file(file_path: Path) -> PylintConfigFileData: for opt, values in sections_values.items(): if isinstance(values, dict): for config, value in values.items(): - value = _parse_rich_type_value(value) - config_content[config] = value - options += [f"--{config}", value] + if ( + isinstance(value, bool) + and store_true_options + and config in store_true_options + ): + config_content[config] = str(value) + if value: + options.append(f"--{config}") + else: + value = _parse_rich_type_value(value) + config_content[config] = value + options += [f"--{config}", value] else: - values = _parse_rich_type_value(values) - config_content[opt] = values - options += [f"--{opt}", values] + if ( + isinstance(values, bool) + and store_true_options + and opt in store_true_options + ): + config_content[opt] = str(values) + if values: + options.append(f"--{opt}") + else: + values = _parse_rich_type_value(values) + config_content[opt] = values + options += [f"--{opt}", values] return config_content, options @staticmethod def parse_config_file( - file_path: Path | None, verbose: bool + file_path: Path | None, + verbose: bool, + store_true_options: set[str] | None = None, ) -> PylintConfigFileData: """Parse a config file and return str-str pairs. @@ -109,7 +132,7 @@ def parse_config_file( print(f"Using config file {file_path}", file=sys.stderr) if file_path.suffix == ".toml": - return _RawConfParser.parse_toml_file(file_path) + return _RawConfParser.parse_toml_file(file_path, store_true_options) return _RawConfParser.parse_ini_file(file_path) @@ -122,8 +145,18 @@ def __init__(self, verbose: bool, linter: PyLinter) -> None: def parse_config_file(self, file_path: Path | None) -> PylintConfigFileData: """Parse a config file and return str-str pairs.""" + # Build a set of store_true option names (bare, without --) + # so parse_toml_file can handle boolean values correctly. + store_true_options: set[str] = set() + for action in self.linter._arg_parser._actions: + if isinstance(action, argparse._StoreTrueAction): + for opt_string in action.option_strings: + store_true_options.add(opt_string.lstrip("-")) + try: - return _RawConfParser.parse_config_file(file_path, self.verbose_mode) + return _RawConfParser.parse_config_file( + file_path, self.verbose_mode, store_true_options + ) except (configparser.Error, tomllib.TOMLDecodeError) as e: self.linter.add_message("config-parse-error", line=0, args=str(e)) return {}, [] diff --git a/tests/config/functional/toml/issue_8460/boolean_false_value.result.json b/tests/config/functional/toml/issue_8460/boolean_false_value.result.json new file mode 100644 index 0000000000..b6a2b7ac3f --- /dev/null +++ b/tests/config/functional/toml/issue_8460/boolean_false_value.result.json @@ -0,0 +1,3 @@ +{ + "exit_zero": false +} diff --git a/tests/config/functional/toml/issue_8460/boolean_false_value.toml b/tests/config/functional/toml/issue_8460/boolean_false_value.toml new file mode 100644 index 0000000000..57daf6bd9a --- /dev/null +++ b/tests/config/functional/toml/issue_8460/boolean_false_value.toml @@ -0,0 +1,6 @@ +# Test that boolean false values in TOML config are properly respected +# for store_true options. Setting exit-zero = false should NOT cause +# pylint to always exit with code 0. + +[tool.pylint.main] +exit-zero = false diff --git a/tests/config/functional/toml/issue_8460/boolean_true_value.result.json b/tests/config/functional/toml/issue_8460/boolean_true_value.result.json new file mode 100644 index 0000000000..a7eb819959 --- /dev/null +++ b/tests/config/functional/toml/issue_8460/boolean_true_value.result.json @@ -0,0 +1,3 @@ +{ + "exit_zero": true +} diff --git a/tests/config/functional/toml/issue_8460/boolean_true_value.toml b/tests/config/functional/toml/issue_8460/boolean_true_value.toml new file mode 100644 index 0000000000..f459cd63ca --- /dev/null +++ b/tests/config/functional/toml/issue_8460/boolean_true_value.toml @@ -0,0 +1,5 @@ +# Test that boolean true values in TOML config still work correctly +# for store_true options. + +[tool.pylint.main] +exit-zero = true