Coverage for C:\Repos\ekr-pylint\pylint\config\callback_actions.py: 46%
120 statements
« prev ^ index » next coverage.py v6.4, created at 2022-05-24 10:21 -0500
« prev ^ index » next coverage.py v6.4, created at 2022-05-24 10:21 -0500
1# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
2# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
3# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
5# pylint: disable=too-many-arguments, redefined-builtin, duplicate-code
7"""Callback actions for various options."""
9from __future__ import annotations
11import abc
12import argparse
13import sys
14import warnings
15from collections.abc import Sequence
16from pathlib import Path
17from typing import TYPE_CHECKING, Any
19from pylint import exceptions, extensions, interfaces, utils
21if TYPE_CHECKING:
22 from pylint.config.help_formatter import _HelpFormatter
23 from pylint.lint import PyLinter
24 from pylint.lint.run import Run
27class _CallbackAction(argparse.Action):
28 """Custom callback action."""
30 @abc.abstractmethod
31 def __call__(
32 self,
33 parser: argparse.ArgumentParser,
34 namespace: argparse.Namespace,
35 values: str | Sequence[Any] | None,
36 option_string: str | None = None,
37 ) -> None:
38 raise NotImplementedError # pragma: no cover
41class _DoNothingAction(_CallbackAction):
42 """Action that just passes.
44 This action is used to allow pre-processing of certain options
45 without erroring when they are then processed again by argparse.
46 """
48 def __call__(
49 self,
50 parser: argparse.ArgumentParser,
51 namespace: argparse.Namespace,
52 values: str | Sequence[Any] | None,
53 option_string: str | None = None,
54 ) -> None:
55 return None
58class _ExtendAction(argparse._AppendAction):
59 """Action that adds the value to a pre-existing list.
61 It is directly copied from the stdlib implementation which is only available
62 on 3.8+.
63 """
65 def __call__(
66 self,
67 parser: argparse.ArgumentParser,
68 namespace: argparse.Namespace,
69 values: str | Sequence[Any] | None,
70 option_string: str | None = None,
71 ) -> None:
72 assert isinstance(values, (tuple, list))
73 current = getattr(namespace, self.dest, [])
74 assert isinstance(current, list)
75 current.extend(values)
76 setattr(namespace, self.dest, current)
79class _AccessRunObjectAction(_CallbackAction):
80 """Action that has access to the Run object."""
82 def __init__(
83 self,
84 option_strings: Sequence[str],
85 dest: str,
86 nargs: None = None,
87 const: None = None,
88 default: None = None,
89 type: None = None,
90 choices: None = None,
91 required: bool = False,
92 help: str = "",
93 metavar: str = "",
94 **kwargs: Run,
95 ) -> None:
96 self.run = kwargs["Run"]
98 super().__init__(
99 option_strings,
100 dest,
101 0,
102 const,
103 default,
104 type,
105 choices,
106 required,
107 help,
108 metavar,
109 )
111 @abc.abstractmethod
112 def __call__(
113 self,
114 parser: argparse.ArgumentParser,
115 namespace: argparse.Namespace,
116 values: str | Sequence[Any] | None,
117 option_string: str | None = None,
118 ) -> None:
119 raise NotImplementedError # pragma: no cover
122class _MessageHelpAction(_CallbackAction):
123 """Display the help message of a message."""
125 def __init__(
126 self,
127 option_strings: Sequence[str],
128 dest: str,
129 nargs: None = None,
130 const: None = None,
131 default: None = None,
132 type: None = None,
133 choices: None = None,
134 required: bool = False,
135 help: str = "",
136 metavar: str = "",
137 **kwargs: Run,
138 ) -> None:
139 self.run = kwargs["Run"]
140 super().__init__(
141 option_strings,
142 dest,
143 "+",
144 const,
145 default,
146 type,
147 choices,
148 required,
149 help,
150 metavar,
151 )
153 def __call__(
154 self,
155 parser: argparse.ArgumentParser,
156 namespace: argparse.Namespace,
157 values: str | Sequence[str] | None,
158 option_string: str | None = "--help-msg",
159 ) -> None:
160 assert isinstance(values, (list, tuple))
161 self.run.linter.msgs_store.help_message(values)
162 sys.exit(0)
165class _ListMessagesAction(_AccessRunObjectAction):
166 """Display all available messages."""
168 def __call__(
169 self,
170 parser: argparse.ArgumentParser,
171 namespace: argparse.Namespace,
172 values: str | Sequence[Any] | None,
173 option_string: str | None = "--list-enabled",
174 ) -> None:
175 self.run.linter.msgs_store.list_messages()
176 sys.exit(0)
179class _ListMessagesEnabledAction(_AccessRunObjectAction):
180 """Display all enabled messages."""
182 def __call__(
183 self,
184 parser: argparse.ArgumentParser,
185 namespace: argparse.Namespace,
186 values: str | Sequence[Any] | None,
187 option_string: str | None = "--list-msgs-enabled",
188 ) -> None:
189 self.run.linter.list_messages_enabled()
190 sys.exit(0)
193class _ListCheckGroupsAction(_AccessRunObjectAction):
194 """Display all the check groups that pylint knows about."""
196 def __call__(
197 self,
198 parser: argparse.ArgumentParser,
199 namespace: argparse.Namespace,
200 values: str | Sequence[Any] | None,
201 option_string: str | None = "--list-groups",
202 ) -> None:
203 for check in self.run.linter.get_checker_names():
204 print(check)
205 sys.exit(0)
208class _ListConfidenceLevelsAction(_AccessRunObjectAction):
209 """Display all the confidence levels that pylint knows about."""
211 def __call__(
212 self,
213 parser: argparse.ArgumentParser,
214 namespace: argparse.Namespace,
215 values: str | Sequence[Any] | None,
216 option_string: str | None = "--list-conf-levels",
217 ) -> None:
218 for level in interfaces.CONFIDENCE_LEVELS:
219 print(f"%-18s: {level}")
220 sys.exit(0)
223class _ListExtensionsAction(_AccessRunObjectAction):
224 """Display all extensions under pylint.extensions."""
226 def __call__(
227 self,
228 parser: argparse.ArgumentParser,
229 namespace: argparse.Namespace,
230 values: str | Sequence[Any] | None,
231 option_string: str | None = "--list-extensions",
232 ) -> None:
233 for filename in Path(extensions.__file__).parent.iterdir():
234 if filename.suffix == ".py" and not filename.stem.startswith("_"):
235 extension_name, _, _ = filename.stem.partition(".")
236 print(f"pylint.extensions.{extension_name}")
237 sys.exit(0)
240class _FullDocumentationAction(_AccessRunObjectAction):
241 """Display the full documentation."""
243 def __call__(
244 self,
245 parser: argparse.ArgumentParser,
246 namespace: argparse.Namespace,
247 values: str | Sequence[Any] | None,
248 option_string: str | None = "--full-documentation",
249 ) -> None:
250 utils.print_full_documentation(self.run.linter)
251 sys.exit(0)
254class _GenerateRCFileAction(_AccessRunObjectAction):
255 """Generate a pylintrc file."""
257 def __call__(
258 self,
259 parser: argparse.ArgumentParser,
260 namespace: argparse.Namespace,
261 values: str | Sequence[Any] | None,
262 option_string: str | None = "--generate-rcfile",
263 ) -> None:
264 # TODO: 2.15: Deprecate this after discussion about this removal has been completed.
265 with warnings.catch_warnings():
266 warnings.filterwarnings("ignore", category=DeprecationWarning)
267 self.run.linter.generate_config(skipsections=("Commands",))
268 sys.exit(0)
271class _GenerateConfigFileAction(_AccessRunObjectAction):
272 """Generate a .toml format configuration file."""
274 def __call__(
275 self,
276 parser: argparse.ArgumentParser,
277 namespace: argparse.Namespace,
278 values: str | Sequence[Any] | None,
279 option_string: str | None = "--generate-toml-config",
280 ) -> None:
281 self.run.linter._generate_config_file()
282 sys.exit(0)
285class _ErrorsOnlyModeAction(_AccessRunObjectAction):
286 """Turn on errors-only mode.
288 Error mode:
289 * disable all but error messages
290 * disable the 'miscellaneous' checker which can be safely deactivated in
291 debug
292 * disable reports
293 * do not save execution information
294 """
296 def __call__(
297 self,
298 parser: argparse.ArgumentParser,
299 namespace: argparse.Namespace,
300 values: str | Sequence[Any] | None,
301 option_string: str | None = "--errors-only",
302 ) -> None:
303 self.run.linter._error_mode = True
306class _LongHelpAction(_AccessRunObjectAction):
307 """Display the long help message."""
309 def __call__(
310 self,
311 parser: argparse.ArgumentParser,
312 namespace: argparse.Namespace,
313 values: str | Sequence[Any] | None,
314 option_string: str | None = "--long-help",
315 ) -> None:
316 formatter: _HelpFormatter = self.run.linter._arg_parser._get_formatter() # type: ignore[assignment]
318 # Add extra info as epilog to the help message
319 self.run.linter._arg_parser.epilog = formatter.get_long_description()
320 print(self.run.linter.help())
322 sys.exit(0)
325class _AccessLinterObjectAction(_CallbackAction):
326 """Action that has access to the Linter object."""
328 def __init__(
329 self,
330 option_strings: Sequence[str],
331 dest: str,
332 nargs: None = None,
333 const: None = None,
334 default: None = None,
335 type: None = None,
336 choices: None = None,
337 required: bool = False,
338 help: str = "",
339 metavar: str = "",
340 **kwargs: PyLinter,
341 ) -> None:
342 self.linter = kwargs["linter"]
344 super().__init__(
345 option_strings,
346 dest,
347 1,
348 const,
349 default,
350 type,
351 choices,
352 required,
353 help,
354 metavar,
355 )
357 @abc.abstractmethod
358 def __call__(
359 self,
360 parser: argparse.ArgumentParser,
361 namespace: argparse.Namespace,
362 values: str | Sequence[Any] | None,
363 option_string: str | None = None,
364 ) -> None:
365 raise NotImplementedError # pragma: no cover
368class _DisableAction(_AccessLinterObjectAction):
369 """Callback action for disabling a message."""
371 def __call__(
372 self,
373 parser: argparse.ArgumentParser,
374 namespace: argparse.Namespace,
375 values: str | Sequence[Any] | None,
376 option_string: str | None = "--disable",
377 ) -> None:
378 assert isinstance(values, (tuple, list))
379 msgids = utils._check_csv(values[0])
380 for msgid in msgids:
381 try:
382 self.linter.disable(msgid)
383 except exceptions.UnknownMessageError:
384 msg = f"{option_string}. Don't recognize message {msgid}."
385 self.linter.add_message("bad-option-value", args=msg, line=0)
388class _EnableAction(_AccessLinterObjectAction):
389 """Callback action for enabling a message."""
391 def __call__(
392 self,
393 parser: argparse.ArgumentParser,
394 namespace: argparse.Namespace,
395 values: str | Sequence[Any] | None,
396 option_string: str | None = "--enable",
397 ) -> None:
398 assert isinstance(values, (tuple, list))
399 msgids = utils._check_csv(values[0])
400 for msgid in msgids:
401 try:
402 self.linter.enable(msgid)
403 except exceptions.UnknownMessageError:
404 msg = f"{option_string}. Don't recognize message {msgid}."
405 self.linter.add_message("bad-option-value", args=msg, line=0)
408class _OutputFormatAction(_AccessLinterObjectAction):
409 """Callback action for setting the output format."""
411 def __call__(
412 self,
413 parser: argparse.ArgumentParser,
414 namespace: argparse.Namespace,
415 values: str | Sequence[Any] | None,
416 option_string: str | None = "--enable",
417 ) -> None:
418 assert isinstance(values, (tuple, list))
419 assert isinstance(
420 values[0], str
421 ), "'output-format' should be a comma separated string of reporters"
422 self.linter._load_reporters(values[0])