Skip to content

Commit 1a20bc5

Browse files
Pylint fix for invalid TOML config (#4720)
* Fix crashes during toml configuration parsing Add test for current 'pyproject.toml' issues. Add a 'bad-configuration-section' message for bad toml configuration We can detect bad top level option when reading the toml but we do not catch all the problem in toml because we don't know what is expected so we can't recommend. See #5259 Co-authored-by: Daniël van Noord <[email protected]>
1 parent 8e15c1d commit 1a20bc5

17 files changed

+94
-5
lines changed

CONTRIBUTORS.txt

+3
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ contributors:
529529

530530
* Marcin Kurczewski (rr-): contributor
531531

532+
* Tanvi Moharir: contributor
533+
- Fix for invalid toml config
534+
532535
* Eisuke Kawashima (e-kwsm): contributor
533536

534537
* Daniel van Noord (DanielNoord): contributor

ChangeLog

+11
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,17 @@ Release date: TBA
158158

159159
Closes #5261
160160

161+
* Crashes when a list is encountered in a toml configuration do not happen anymore.
162+
163+
Closes #4580
164+
165+
* A new ``bad-configuration-section`` checker was added that will emit for misplaced option
166+
in pylint's top level namespace for toml configuration. Top-level dictionaries or option defined
167+
in the wrong section will still silently not be taken into account, which is tracked in a
168+
follow-up issue.
169+
170+
Follow-up in #5259
171+
161172
* Added new checker ``useless-with-lock`` to find incorrect usage of with statement and threading module locks.
162173
Emitted when ``with threading.Lock():`` is used instead of ``with lock_instance:``.
163174

doc/whatsnew/2.12.rst

+11
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ New checkers
5656

5757
Closes #5208
5858

59+
* A new ``bad-configuration-section`` checker was added that will emit for misplaced option
60+
in pylint's top level namespace for toml configuration. Top-level dictionaries or option defined
61+
in the wrong section will still silently not be taken into account, which is tracked in a
62+
follow-up issue.
63+
64+
Follow-up in #5259
65+
5966
Removed checkers
6067
================
6168

@@ -162,4 +169,8 @@ Other Changes
162169

163170
Closes #5216
164171

172+
* Crashes when a list is encountered in a toml configuration do not happen anymore.
173+
174+
Closes #4580
175+
165176
* Make yn validator case insensitive, to allow for ``True`` and ``False`` in config files.

pylint/config/option_manager_mixin.py

+16-5
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,8 @@ def read_config_file(self, config_file=None, verbose=None):
293293
msg = "No config file found, using default configuration"
294294
print(msg, file=sys.stderr)
295295

296-
@staticmethod
297296
def _parse_toml(
298-
config_file: Union[Path, str], parser: configparser.ConfigParser
297+
self, config_file: Union[Path, str], parser: configparser.ConfigParser
299298
) -> None:
300299
"""Parse and handle errors of a toml configuration file."""
301300
with open(config_file, encoding="utf-8") as fp:
@@ -305,16 +304,28 @@ def _parse_toml(
305304
except KeyError:
306305
return
307306
for section, values in sections_values.items():
307+
section_name = section.upper()
308308
# TOML has rich types, convert values to
309309
# strings as ConfigParser expects.
310+
if not isinstance(values, dict):
311+
# This class is a mixin: add_message comes from the `PyLinter` class
312+
self.add_message( # type: ignore
313+
"bad-configuration-section", line=0, args=(section, values)
314+
)
315+
continue
310316
for option, value in values.items():
311317
if isinstance(value, bool):
312318
values[option] = "yes" if value else "no"
313-
elif isinstance(value, (int, float)):
314-
values[option] = str(value)
315319
elif isinstance(value, list):
316320
values[option] = ",".join(value)
317-
parser._sections[section.upper()] = values # type: ignore
321+
else:
322+
values[option] = str(value)
323+
for option, value in values.items():
324+
try:
325+
parser.set(section_name, option, value=value)
326+
except configparser.NoSectionError:
327+
parser.add_section(section_name)
328+
parser.set(section_name, option, value=value)
318329

319330
def load_config_file(self):
320331
"""Dispatch values previously read from a configuration file to each

pylint/lint/pylinter.py

+5
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ def _load_reporter_by_class(reporter_class: str) -> type:
158158
"bad-plugin-value",
159159
"Used when a bad value is used in 'load-plugins'.",
160160
),
161+
"E0014": (
162+
"Out-of-place setting encountered in top level configuration-section '%s' : '%s'",
163+
"bad-configuration-section",
164+
"Used when we detect a setting in the top level of a toml configuration that shouldn't be there.",
165+
),
161166
}
162167

163168

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[tool.pylint.basic]
2+
name-group = { "a"="b" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[tool.pylint.imports]
2+
preferred-modules = { "a"="b" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
************* Module {abspath}
2+
{relpath}:1:0: E0014: Out-of-place setting encountered in top level configuration-section 'load-plugins' : '[]' (bad-configuration-section)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[tool.pylint]
2+
# load-plugins does not belong in top level section
3+
load-plugins = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
************* Module {abspath}
2+
{relpath}:1:0: E0014: Out-of-place setting encountered in top level configuration-section 'load-plugins' : '[]' (bad-configuration-section)
3+
{relpath}:1:0: E0014: Out-of-place setting encountered in top level configuration-section 'disable' : 'logging-not-lazy,logging-format-interpolation' (bad-configuration-section)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[tool.pylint]
2+
# Both disable and load-plugins do not belong in the top level section
3+
load-plugins = []
4+
disable = "logging-not-lazy,logging-format-interpolation"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"functional_append": {
3+
"disable": [["logging-not-lazy"], ["logging-format-interpolation"]]
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Both disable and load-plugins do not belong in the imports section
2+
# TODO This should be fixed in #5259
3+
[tool.pylint."imports"]
4+
disable = [
5+
"logging-not-lazy",
6+
"logging-format-interpolation",
7+
]
8+
preferred-modules = { "a"="b" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"functional_append": {
3+
"disable": [["logging-not-lazy"], ["logging-format-interpolation"]]
4+
},
5+
"jobs": 10,
6+
"reports": true
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[tool.pylint."messages control"]
2+
disable = [
3+
"logging-not-lazy",
4+
"logging-format-interpolation",
5+
]
6+
jobs = 10
7+
reports = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
************* Module {abspath}
2+
{relpath}:1:0: E0014: Out-of-place setting encountered in top level configuration-section 'disable' : 'logging-not-lazy,logging-format-interpolation' (bad-configuration-section)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[tool.pylint]
2+
# disable does not belong in top level section
3+
disable = "logging-not-lazy,logging-format-interpolation"

0 commit comments

Comments
 (0)