diff options
author | Damien Baty <damien.baty@polyconseil.fr> | 2020-05-12 18:13:13 +0200 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2020-05-16 09:47:49 +0200 |
commit | ffb6006bfb77f8178f0c7301be2db7b844e9dee3 (patch) | |
tree | 5884602a61902a25db86b9e70a45a99fe41b4179 | |
parent | c4c96ec135ccc4ea33fbffd33587b5785df2a468 (diff) | |
download | pylint-git-ffb6006bfb77f8178f0c7301be2db7b844e9dee3.tar.gz |
config: Handle rich (non-string) types in TOML file
Fixes #3538
Before that, we had to use strings in a TOML configuration file, like
this:
enable = "use-symbolic-message-instead,useless-suppression"
jobs = "10"
suggestion-mode = "no"
TOML supports rich types like list, integer and boolean. They make for
a more readable and less error-prone file. We can now express the same
configuration like this:
enable = [
"use-symbolic-message-instead",
"useless-suppression",
]
jobs = 10
suggestion-mode = false
-rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | pylint/config.py | 11 | ||||
-rw-r--r-- | tests/test_config.py | 102 |
4 files changed, 100 insertions, 24 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 420c62417..350b7d1c0 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -381,3 +381,5 @@ contributors: * Yang Yang: contributor * Andrew J. Simmons (anjsimmo): contributor + +* Damien Baty: contributor @@ -23,6 +23,15 @@ Release date: TBA Close #3547 +* In a TOML configuration file, it's now possible to use rich (non-string) types, such as list, integer or boolean instead of strings. For example, one can now define a *list* of message identifiers to enable like this:: + + enable = [ + "use-symbolic-message-instead", + "useless-suppression", + ] + + Close #3538 + What's New in Pylint 2.5.2? =========================== diff --git a/pylint/config.py b/pylint/config.py index 452ec3dfc..743247cd3 100644 --- a/pylint/config.py +++ b/pylint/config.py @@ -741,7 +741,7 @@ class OptionsManagerMixIn: raise OSError("The config file {:s} doesn't exist!".format(config_file)) use_config_file = config_file and os.path.exists(config_file) - if use_config_file: + if use_config_file: # pylint: disable=too-many-nested-blocks parser = self.cfgfile_parser if config_file.endswith(".toml"): @@ -754,6 +754,15 @@ class OptionsManagerMixIn: pass else: for section, values in sections_values.items(): + # TOML has rich types, convert values to + # strings as ConfigParser expects. + for option, value in values.items(): + if isinstance(value, bool): + values[option] = "yes" if value else "no" + elif isinstance(value, int): + values[option] = str(value) + elif isinstance(value, list): + values[option] = ",".join(value) parser._sections[section.upper()] = values else: # Use this encoding in order to strip the BOM marker, if any. diff --git a/tests/test_config.py b/tests/test_config.py index 8ea626d03..ecfac3328 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,37 +1,93 @@ +# pylint: disable=missing-module-docstring, missing-function-docstring, protected-access import unittest.mock import pylint.lint -def test_can_read_toml(tmp_path): - config_file = tmp_path / "pyproject.toml" +def check_configuration_file_reader(config_file): + """Initialize pylint with the given configuration file and check that + what we initialized the linter with what was expected. + """ + args = ["--rcfile", str(config_file), __file__] + # If we used `pytest.raises(SystemExit)`, the `runner` variable + # would not be accessible outside the `with` block. + with unittest.mock.patch("sys.exit") as mocked_exit: + # Do not actually run checks, that could be slow. Do not mock + # `Pylinter.check`: it calls `Pylinter.initialize` which is + # needed to properly set up messages inclusion/exclusion + # in `_msg_states`, used by `is_message_enabled`. + with unittest.mock.patch("pylint.lint.pylinter.check_parallel"): + runner = pylint.lint.Run(args) + + # "logging-not-lazy" and "logging-format-interpolation" + expected_disabled = {"W1201", "W1202"} + for msgid in expected_disabled: + assert not runner.linter.is_message_enabled(msgid) + assert runner.linter.config.jobs == 10 + assert runner.linter.config.reports + + mocked_exit.assert_called_once_with(0) + return runner + + +def test_can_read_ini(tmp_path): + # Check that we can read the "regular" INI .pylintrc file + config_file = tmp_path / ".pylintrc" config_file.write_text( - "[tool.pylint.'messages control']\n" - "disable='all'\n" - "enable='missing-module-docstring'\n" - "jobs=10\n" + """ +[messages control] +disable = logging-not-lazy,logging-format-interpolation +jobs = 10 +reports = yes +""" ) - linter = pylint.lint.PyLinter() - linter.global_set_option = unittest.mock.MagicMock() - linter.read_config_file(str(config_file)) - - assert linter.global_set_option.called_with("disable", "all") - assert linter.global_set_option.called_with("enable", "missing-module-docstring") - assert linter.global_set_option.called_with("jobs", 10) + check_configuration_file_reader(config_file) def test_can_read_setup_cfg(tmp_path): + # Check that we can read a setup.cfg (which is an INI file where + # section names are prefixed with "pylint." config_file = tmp_path / "setup.cfg" config_file.write_text( - "[pylint.messages control]\n" - "disable=all\n" - "enable=missing-module-docstring\n" - "jobs=10\n" + """ +[pylint.messages control] +disable = logging-not-lazy,logging-format-interpolation +jobs = 10 +reports = yes +""" ) - linter = pylint.lint.PyLinter() - linter.global_set_option = unittest.mock.MagicMock() - linter.read_config_file(str(config_file)) + check_configuration_file_reader(config_file) - assert linter.global_set_option.called_with("disable", "all") - assert linter.global_set_option.called_with("enable", "missing-module-docstring") - assert linter.global_set_option.called_with("jobs", 10) + +def test_can_read_toml(tmp_path): + # Check that we can read a TOML file where lists and integers are + # expressed as strings. + config_file = tmp_path / "pyproject.toml" + config_file.write_text( + """ +[tool.pylint."messages control"] +disable = "logging-not-lazy,logging-format-interpolation" +jobs = "10" +reports = "yes" +""" + ) + check_configuration_file_reader(config_file) + + +def test_can_read_toml_rich_types(tmp_path): + # Check that we can read a TOML file where lists, integers and + # booleans are expressed as such (and not as strings), using TOML + # type system. + config_file = tmp_path / "pyproject.toml" + config_file.write_text( + """ +[tool.pylint."messages control"] +disable = [ + "logging-not-lazy", + "logging-format-interpolation", +] +jobs = 10 +reports = true +""" + ) + check_configuration_file_reader(config_file) |