Skip to content

Commit 4438029

Browse files
authored
Add a --generate-toml-config option (#6199)
1 parent 00321dc commit 4438029

File tree

11 files changed

+197
-11
lines changed

11 files changed

+197
-11
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ Release date: TBA
8585

8686
Closes #5205
8787

88+
* Added the ``generate-toml-config`` option.
89+
90+
Ref #5462
91+
8892
* Added new checker ``unnecessary-list-index-lookup`` for indexing into a list while
8993
iterating over ``enumerate()``.
9094

doc/faq.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,16 @@ localized using the following rules:
100100

101101
* ".pylint.d" directory in the current directory
102102

103-
3.3 How do I find the option name (for pylintrc) corresponding to a specific command line option?
103+
3.3 How do I find the option name corresponding to a specific command line option?
104104
--------------------------------------------------------------------------------------------------------
105105

106-
You can generate a sample pylintrc file with --generate-rcfile
106+
You can generate a sample configuration file with ``--generate-toml-config``.
107107
Every option present on the command line before this will be included in
108-
the rc file
108+
the toml file
109109

110110
For example::
111111

112-
pylint --disable=bare-except,invalid-name --class-rgx='[A-Z][a-z]+' --generate-rcfile
112+
pylint --disable=bare-except,invalid-name --class-rgx='[A-Z][a-z]+' --generate-toml-config
113113

114114
3.4 I'd rather not run Pylint from the command line. Can I integrate it with my editor?
115115
---------------------------------------------------------------------------------------

doc/intro.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ The best way to tackle pylint's verboseness is to:
5353
all convention messages is simple as a ``--disable=C`` option added to pylint
5454
command.
5555

56-
* create a custom configuration file, tailored to your needs. You can generate
57-
one using pylint's command ``--generate-rcfile``.
56+
* manage the configuration through a configuration file. With the option
57+
``generate-toml-config`` you can create a piece of ``.toml`` text to put
58+
in your ``pyproject.toml`` file.

doc/tutorial.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ A couple of the options that we'll focus on here are: ::
5959

6060
Commands:
6161
--help-msg=<msg-id>
62-
--generate-rcfile
62+
--generate-toml-config
6363
Messages control:
6464
--disable=<msg-ids>
6565
Reports:
@@ -273,7 +273,8 @@ example but go ahead and `read up`_ on them if you want.
273273
It would really be a pain to specify that regex on the command line all the time, particularly if we're using many other options.
274274
That's what a configuration file is for. We can configure our Pylint to
275275
store our options for us so we don't have to declare them on the command line. Using a configuration file is a nice way of formalizing your rules and
276-
quickly sharing them with others. Invoking ``pylint --generate-rcfile`` will create a sample rcfile with all the options set and explained in comments.
276+
quickly sharing them with others. Invoking ``pylint --generate-toml-config`` will create a sample ``.toml`` section with all the options set and explained in comments.
277+
This can then be added to your ``pyproject.toml`` file or any other ``.toml`` file pointed to with the ``--rcfile`` option.
277278

278279
That's it for the basic intro. More tutorials will follow.
279280

doc/user_guide/run.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,12 @@ configuration file in the following order and uses the first one it finds:
178178

179179
#. ``/etc/pylintrc``
180180

181-
The ``--generate-rcfile`` option will generate a commented configuration file
181+
The ``--generate-toml-config`` option will generate a commented configuration file
182182
on standard output according to the current configuration and exit. This
183183
includes:
184184

185185
* Any configuration file found as explained above
186-
* Options appearing before ``--generate-rcfile`` on the Pylint command line
186+
* Options appearing before ``--generate-toml-config`` on the Pylint command line
187187

188188
Of course you can also start with the default values and hand-tune the
189189
configuration.

doc/whatsnew/2.14.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ Other Changes
9595

9696
Ref #5392
9797

98+
* Added the ``generate-toml-config`` option.
99+
100+
Ref #5462
101+
98102
* Fix false negative for ``bad-string-format-type`` if the value to be formatted is passed in
99103
as a variable holding a constant.
100104

pylint/config/arguments_manager.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
import copy
1111
import optparse # pylint: disable=deprecated-module
1212
import os
13+
import re
1314
import sys
15+
import textwrap
1416
import warnings
1517
from pathlib import Path
1618
from typing import TYPE_CHECKING, Any, Dict, List, Optional, TextIO, Tuple, Union
1719

20+
import tomlkit
21+
1822
from pylint import utils
1923
from pylint.config.argument import (
2024
_Argument,
@@ -595,3 +599,74 @@ def cb_set_provider_option(self, option, opt, value, parser): # pragma: no cove
595599
def global_set_option(self, opt, value):
596600
"""Set option on the correct option provider."""
597601
self._all_options[opt].set_option(opt, value)
602+
603+
def _generate_config_file(self) -> None:
604+
"""Write a configuration file according to the current configuration into stdout."""
605+
toml_doc = tomlkit.document()
606+
pylint_tool_table = tomlkit.table(is_super_table=True)
607+
toml_doc.add(tomlkit.key(["tool", "pylint"]), pylint_tool_table)
608+
609+
for group in sorted(
610+
self._arg_parser._action_groups,
611+
key=lambda x: (x.title != "Master", x.title),
612+
):
613+
# Skip the options section with the --help option
614+
if group.title == "options":
615+
continue
616+
617+
# Skip sections without options such as "positional arguments"
618+
if not group._group_actions:
619+
continue
620+
621+
group_table = tomlkit.table()
622+
for action in sorted(
623+
group._group_actions, key=lambda x: x.option_strings[0][2:]
624+
):
625+
optname = action.option_strings[0][2:]
626+
627+
# We skip old name options that don't have their own optdict
628+
try:
629+
optdict = self._option_dicts[optname]
630+
except KeyError:
631+
continue
632+
633+
if optdict.get("hide_from_config_file"):
634+
continue
635+
636+
# Add help comment
637+
help_msg = optdict.get("help", "")
638+
assert isinstance(help_msg, str)
639+
help_text = textwrap.wrap(help_msg, width=79)
640+
for line in help_text:
641+
group_table.add(tomlkit.comment(line))
642+
643+
# Get current value of option
644+
value = getattr(self.namespace, optname.replace("-", "_"))
645+
646+
# Create a comment if the option has no value
647+
if not value:
648+
group_table.add(tomlkit.comment(f"{optname} ="))
649+
group_table.add(tomlkit.nl())
650+
continue
651+
652+
# Tomlkit doesn't support regular expressions
653+
if isinstance(value, re.Pattern):
654+
value = value.pattern
655+
elif isinstance(value, (list, tuple)) and isinstance(
656+
value[0], re.Pattern
657+
):
658+
value = [i.pattern for i in value]
659+
660+
# Add to table
661+
group_table.add(optname, value)
662+
group_table.add(tomlkit.nl())
663+
664+
assert group.title
665+
pylint_tool_table.add(group.title.lower(), group_table)
666+
667+
toml_string = tomlkit.dumps(toml_doc)
668+
669+
# Make sure the string we produce is valid toml and can be parsed
670+
tomllib.loads(toml_string)
671+
672+
print(toml_string)

pylint/config/callback_actions.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,20 @@ def __call__(
245245
sys.exit(0)
246246

247247

248+
class _GenerateConfigFileAction(_AccessRunObjectAction):
249+
"""Generate a .toml format configuration file."""
250+
251+
def __call__(
252+
self,
253+
parser: argparse.ArgumentParser,
254+
namespace: argparse.Namespace,
255+
values: Union[str, Sequence[Any], None],
256+
option_string: Optional[str] = "--generate-toml-config",
257+
) -> None:
258+
self.run.linter._generate_config_file()
259+
sys.exit(0)
260+
261+
248262
class _ErrorsOnlyModeAction(_AccessRunObjectAction):
249263
"""Turn on errors-only mode.
250264

pylint/lint/run.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
_DoNothingAction,
1313
_ErrorsOnlyModeAction,
1414
_FullDocumentationAction,
15+
_GenerateConfigFileAction,
1516
_GenerateRCFileAction,
1617
_ListCheckGroupsAction,
1718
_ListConfidenceLevelsAction,
@@ -104,6 +105,7 @@ def __init__(
104105
"callback": Run._not_implemented_callback,
105106
"group": "Commands",
106107
"help": "Specify a configuration file to load.",
108+
"hide_from_config_file": True,
107109
},
108110
),
109111
(
@@ -114,6 +116,7 @@ def __init__(
114116
"callback": Run._not_implemented_callback,
115117
"group": "Commands",
116118
"help": "Specify an output file.",
119+
"hide_from_config_file": True,
117120
},
118121
),
119122
(
@@ -135,6 +138,7 @@ def __init__(
135138
"group": "Commands",
136139
"help": "Display a help message for the given message id and "
137140
"exit. The value may be a comma separated list of message ids.",
141+
"hide_from_config_file": True,
138142
},
139143
),
140144
(
@@ -146,6 +150,7 @@ def __init__(
146150
"group": "Commands",
147151
"help": "Display a list of all pylint's messages divided by whether "
148152
"they are emittable with the given interpreter.",
153+
"hide_from_config_file": True,
149154
},
150155
),
151156
(
@@ -157,6 +162,7 @@ def __init__(
157162
"group": "Commands",
158163
"help": "Display a list of what messages are enabled, "
159164
"disabled and non-emittable with the given configuration.",
165+
"hide_from_config_file": True,
160166
},
161167
),
162168
(
@@ -167,6 +173,7 @@ def __init__(
167173
"callback": Run._not_implemented_callback,
168174
"group": "Commands",
169175
"help": "List pylint's message groups.",
176+
"hide_from_config_file": True,
170177
},
171178
),
172179
(
@@ -177,6 +184,7 @@ def __init__(
177184
"kwargs": {"Run": self},
178185
"group": "Commands",
179186
"help": "Generate pylint's confidence levels.",
187+
"hide_from_config_file": True,
180188
},
181189
),
182190
(
@@ -187,6 +195,7 @@ def __init__(
187195
"callback": Run._not_implemented_callback,
188196
"group": "Commands",
189197
"help": "List available extensions.",
198+
"hide_from_config_file": True,
190199
},
191200
),
192201
(
@@ -197,6 +206,7 @@ def __init__(
197206
"callback": Run._not_implemented_callback,
198207
"group": "Commands",
199208
"help": "Generate pylint's full documentation.",
209+
"hide_from_config_file": True,
200210
},
201211
),
202212
(
@@ -210,6 +220,21 @@ def __init__(
210220
"the current configuration. You can put other options "
211221
"before this one to get them in the generated "
212222
"configuration.",
223+
"hide_from_config_file": True,
224+
},
225+
),
226+
(
227+
"generate-toml-config",
228+
{
229+
"action": _GenerateConfigFileAction,
230+
"kwargs": {"Run": self},
231+
"callback": Run._not_implemented_callback,
232+
"group": "Commands",
233+
"help": "Generate a sample configuration file according to "
234+
"the current configuration. You can put other options "
235+
"before this one to get them in the generated "
236+
"configuration. The config is in the .toml format.",
237+
"hide_from_config_file": True,
213238
},
214239
),
215240
(
@@ -222,6 +247,7 @@ def __init__(
222247
"help": "In error mode, checkers without error messages are "
223248
"disabled and for others, only the ERROR messages are "
224249
"displayed, and no reports are done by default.",
250+
"hide_from_config_file": True,
225251
},
226252
),
227253
(
@@ -233,6 +259,7 @@ def __init__(
233259
"short": "v",
234260
"help": "In verbose mode, extra non-checker-related info "
235261
"will be displayed.",
262+
"hide_from_config_file": True,
236263
},
237264
),
238265
(
@@ -243,6 +270,7 @@ def __init__(
243270
"callback": Run._not_implemented_callback,
244271
"help": "Load and enable all available extensions. "
245272
"Use --list-extensions to see a list all available extensions.",
273+
"hide_from_config_file": True,
246274
},
247275
),
248276
(
@@ -253,6 +281,7 @@ def __init__(
253281
"callback": Run._not_implemented_callback,
254282
"help": "Show more verbose help.",
255283
"group": "Commands",
284+
"hide_from_config_file": True,
256285
},
257286
),
258287
),

setup.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ install_requires =
5151
isort>=4.2.5,<6
5252
mccabe>=0.6,<0.8
5353
tomli>=1.1.0;python_version<"3.11"
54+
tomlkit>=0.10.1
5455
colorama;sys_platform=="win32"
5556
typing-extensions>=3.10.0;python_version<"3.10"
5657
python_requires = >=3.7.2
@@ -135,6 +136,9 @@ ignore_missing_imports = True
135136
[mypy-git.*]
136137
ignore_missing_imports = True
137138
139+
[mypy-tomlkit]
140+
ignore_missing_imports = True
141+
138142
[mypy-sphinx.*]
139143
ignore_missing_imports = True
140144

0 commit comments

Comments
 (0)