2022-04-02 12:43:17 +00:00
|
|
|
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
|
|
|
|
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
|
|
|
|
|
2022-04-02 20:06:25 +00:00
|
|
|
# pylint: disable=too-many-arguments, redefined-builtin
|
2022-04-02 17:32:21 +00:00
|
|
|
|
2022-04-02 12:43:17 +00:00
|
|
|
"""Callback actions for various options."""
|
|
|
|
|
|
|
|
import abc
|
|
|
|
import argparse
|
2022-04-02 17:32:21 +00:00
|
|
|
import sys
|
2022-04-07 14:14:11 +00:00
|
|
|
import warnings
|
2022-04-02 17:32:21 +00:00
|
|
|
from pathlib import Path
|
|
|
|
from typing import TYPE_CHECKING, Any, Optional, Sequence, Union
|
|
|
|
|
2022-04-12 10:56:42 +00:00
|
|
|
from pylint import exceptions, extensions, interfaces, utils
|
2022-04-02 17:32:21 +00:00
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
2022-04-02 20:06:25 +00:00
|
|
|
from pylint.config.help_formatter import _HelpFormatter
|
2022-04-11 19:50:07 +00:00
|
|
|
from pylint.lint import PyLinter
|
2022-04-02 17:32:21 +00:00
|
|
|
from pylint.lint.run import Run
|
2022-04-02 12:43:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _CallbackAction(argparse.Action):
|
|
|
|
"""Custom callback action."""
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = None,
|
|
|
|
) -> None:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class _DoNothingAction(_CallbackAction):
|
|
|
|
"""Action that just passes.
|
|
|
|
|
|
|
|
This action is used to allow pre-processing of certain options
|
|
|
|
without erroring when they are then processed again by argparse.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = None,
|
|
|
|
) -> None:
|
|
|
|
return None
|
2022-04-02 17:32:21 +00:00
|
|
|
|
|
|
|
|
2022-04-14 06:48:35 +00:00
|
|
|
class _ExtendAction(argparse._AppendAction):
|
|
|
|
"""Action that adds the value to a pre-existing list.
|
|
|
|
|
|
|
|
It is directly copied from the stdlib implementation which is only available
|
|
|
|
on 3.8+.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = None,
|
|
|
|
) -> None:
|
|
|
|
assert isinstance(values, (tuple, list))
|
|
|
|
current = getattr(namespace, self.dest, [])
|
|
|
|
assert isinstance(current, list)
|
|
|
|
current.extend(values)
|
|
|
|
setattr(namespace, self.dest, current)
|
|
|
|
|
|
|
|
|
2022-04-02 17:32:21 +00:00
|
|
|
class _AccessRunObjectAction(_CallbackAction):
|
|
|
|
"""Action that has access to the Run object."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
option_strings: Sequence[str],
|
|
|
|
dest: str,
|
|
|
|
nargs: None = None,
|
|
|
|
const: None = None,
|
|
|
|
default: None = None,
|
2022-04-02 20:06:25 +00:00
|
|
|
type: None = None,
|
2022-04-02 17:32:21 +00:00
|
|
|
choices: None = None,
|
|
|
|
required: bool = False,
|
2022-04-02 20:06:25 +00:00
|
|
|
help: str = "",
|
2022-04-02 17:32:21 +00:00
|
|
|
metavar: str = "",
|
|
|
|
**kwargs: "Run",
|
|
|
|
) -> None:
|
|
|
|
self.run = kwargs["Run"]
|
|
|
|
|
|
|
|
super().__init__(
|
|
|
|
option_strings,
|
|
|
|
dest,
|
|
|
|
0,
|
|
|
|
const,
|
|
|
|
default,
|
2022-04-02 20:06:25 +00:00
|
|
|
type,
|
2022-04-02 17:32:21 +00:00
|
|
|
choices,
|
|
|
|
required,
|
2022-04-02 20:06:25 +00:00
|
|
|
help,
|
2022-04-02 17:32:21 +00:00
|
|
|
metavar,
|
|
|
|
)
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = None,
|
|
|
|
) -> None:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class _MessageHelpAction(_CallbackAction):
|
|
|
|
"""Display the help message of a message."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
option_strings: Sequence[str],
|
|
|
|
dest: str,
|
|
|
|
nargs: None = None,
|
|
|
|
const: None = None,
|
|
|
|
default: None = None,
|
2022-04-02 20:06:25 +00:00
|
|
|
type: None = None,
|
2022-04-02 17:32:21 +00:00
|
|
|
choices: None = None,
|
|
|
|
required: bool = False,
|
2022-04-02 20:06:25 +00:00
|
|
|
help: str = "",
|
2022-04-02 17:32:21 +00:00
|
|
|
metavar: str = "",
|
|
|
|
**kwargs: "Run",
|
|
|
|
) -> None:
|
|
|
|
self.run = kwargs["Run"]
|
|
|
|
super().__init__(
|
|
|
|
option_strings,
|
|
|
|
dest,
|
|
|
|
"+",
|
|
|
|
const,
|
|
|
|
default,
|
2022-04-02 20:06:25 +00:00
|
|
|
type,
|
2022-04-02 17:32:21 +00:00
|
|
|
choices,
|
|
|
|
required,
|
2022-04-02 20:06:25 +00:00
|
|
|
help,
|
2022-04-02 17:32:21 +00:00
|
|
|
metavar,
|
|
|
|
)
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[str], None],
|
|
|
|
option_string: Optional[str] = "--help-msg",
|
|
|
|
) -> None:
|
2022-04-04 08:00:17 +00:00
|
|
|
assert isinstance(values, (list, tuple))
|
|
|
|
self.run.linter.msgs_store.help_message(values)
|
2022-04-02 17:32:21 +00:00
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _ListMessagesAction(_AccessRunObjectAction):
|
|
|
|
"""Display all available messages."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--list-enabled",
|
|
|
|
) -> None:
|
|
|
|
self.run.linter.msgs_store.list_messages()
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _ListMessagesEnabledAction(_AccessRunObjectAction):
|
|
|
|
"""Display all enabled messages."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--list-msgs-enabled",
|
|
|
|
) -> None:
|
|
|
|
self.run.linter.list_messages_enabled()
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _ListCheckGroupsAction(_AccessRunObjectAction):
|
|
|
|
"""Display all the check groups that pylint knows about."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--list-groups",
|
|
|
|
) -> None:
|
|
|
|
for check in self.run.linter.get_checker_names():
|
|
|
|
print(check)
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _ListConfidenceLevelsAction(_AccessRunObjectAction):
|
|
|
|
"""Display all the confidence levels that pylint knows about."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--list-conf-levels",
|
|
|
|
) -> None:
|
|
|
|
for level in interfaces.CONFIDENCE_LEVELS:
|
|
|
|
print(f"%-18s: {level}")
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _ListExtensionsAction(_AccessRunObjectAction):
|
|
|
|
"""Display all extensions under pylint.extensions."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--list-extensions",
|
|
|
|
) -> None:
|
|
|
|
for filename in Path(extensions.__file__).parent.iterdir():
|
|
|
|
if filename.suffix == ".py" and not filename.stem.startswith("_"):
|
|
|
|
extension_name, _, _ = filename.stem.partition(".")
|
|
|
|
print(f"pylint.extensions.{extension_name}")
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _FullDocumentationAction(_AccessRunObjectAction):
|
|
|
|
"""Display the full documentation."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--full-documentation",
|
|
|
|
) -> None:
|
|
|
|
utils.print_full_documentation(self.run.linter)
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
|
|
|
class _GenerateRCFileAction(_AccessRunObjectAction):
|
|
|
|
"""Generate a pylintrc file."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--generate-rcfile",
|
|
|
|
) -> None:
|
2022-04-07 14:14:11 +00:00
|
|
|
# pylint: disable-next=fixme
|
2022-04-13 08:08:07 +00:00
|
|
|
# TODO: Optparse: Deprecate this after discussion about this removal has been completed.
|
2022-04-07 14:14:11 +00:00
|
|
|
with warnings.catch_warnings():
|
|
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
2022-04-13 08:08:07 +00:00
|
|
|
self.run.linter.generate_config(skipsections=("Commands",))
|
2022-04-02 17:32:21 +00:00
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
2022-04-13 19:45:47 +00:00
|
|
|
class _GenerateConfigFileAction(_AccessRunObjectAction):
|
|
|
|
"""Generate a .toml format configuration file."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--generate-toml-config",
|
|
|
|
) -> None:
|
|
|
|
self.run.linter._generate_config_file()
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
|
2022-04-02 17:32:21 +00:00
|
|
|
class _ErrorsOnlyModeAction(_AccessRunObjectAction):
|
|
|
|
"""Turn on errors-only mode.
|
|
|
|
|
|
|
|
Error mode:
|
|
|
|
* disable all but error messages
|
|
|
|
* disable the 'miscellaneous' checker which can be safely deactivated in
|
|
|
|
debug
|
|
|
|
* disable reports
|
|
|
|
* do not save execution information
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--errors-only",
|
|
|
|
) -> None:
|
2022-04-04 13:52:51 +00:00
|
|
|
self.run.linter._error_mode = True
|
2022-04-02 17:32:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _LongHelpAction(_AccessRunObjectAction):
|
|
|
|
"""Display the long help message."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--long-help",
|
|
|
|
) -> None:
|
2022-04-02 20:06:25 +00:00
|
|
|
formatter: "_HelpFormatter" = self.run.linter._arg_parser._get_formatter()
|
|
|
|
|
|
|
|
# Add extra info as epilog to the help message
|
|
|
|
self.run.linter._arg_parser.epilog = formatter.get_long_description()
|
2022-04-07 15:57:16 +00:00
|
|
|
print(self.run.linter.help())
|
2022-04-02 20:06:25 +00:00
|
|
|
|
2022-04-02 17:32:21 +00:00
|
|
|
sys.exit(0)
|
2022-04-11 19:50:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _AccessLinterObjectAction(_CallbackAction):
|
|
|
|
"""Action that has access to the Linter object."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
option_strings: Sequence[str],
|
|
|
|
dest: str,
|
|
|
|
nargs: None = None,
|
|
|
|
const: None = None,
|
|
|
|
default: None = None,
|
|
|
|
type: None = None,
|
|
|
|
choices: None = None,
|
|
|
|
required: bool = False,
|
|
|
|
help: str = "",
|
|
|
|
metavar: str = "",
|
|
|
|
**kwargs: "PyLinter",
|
|
|
|
) -> None:
|
|
|
|
self.linter = kwargs["linter"]
|
|
|
|
|
|
|
|
super().__init__(
|
|
|
|
option_strings,
|
|
|
|
dest,
|
|
|
|
1,
|
|
|
|
const,
|
|
|
|
default,
|
|
|
|
type,
|
|
|
|
choices,
|
|
|
|
required,
|
|
|
|
help,
|
|
|
|
metavar,
|
|
|
|
)
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = None,
|
|
|
|
) -> None:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
2022-04-11 19:53:00 +00:00
|
|
|
class _DisableAction(_AccessLinterObjectAction):
|
|
|
|
"""Callback action for disabling a message."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--disable",
|
|
|
|
) -> None:
|
|
|
|
assert isinstance(values, (tuple, list))
|
2022-04-12 10:56:42 +00:00
|
|
|
msgids = utils._check_csv(values[0])
|
|
|
|
try:
|
|
|
|
for msgid in msgids:
|
|
|
|
self.linter.disable(msgid)
|
|
|
|
except exceptions.UnknownMessageError:
|
|
|
|
# pylint: disable-next=fixme
|
|
|
|
# TODO: Optparse: Raise an informational warning here
|
|
|
|
pass
|
2022-04-11 19:53:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
class _EnableAction(_AccessLinterObjectAction):
|
|
|
|
"""Callback action for enabling a message."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--enable",
|
|
|
|
) -> None:
|
|
|
|
assert isinstance(values, (tuple, list))
|
2022-04-12 10:56:42 +00:00
|
|
|
msgids = utils._check_csv(values[0])
|
|
|
|
try:
|
|
|
|
for msgid in msgids:
|
|
|
|
self.linter.enable(msgid)
|
|
|
|
except exceptions.UnknownMessageError:
|
|
|
|
# pylint: disable-next=fixme
|
|
|
|
# TODO: Optparse: Raise an informational warning here
|
|
|
|
pass
|
2022-04-11 19:53:00 +00:00
|
|
|
|
|
|
|
|
2022-04-11 19:50:07 +00:00
|
|
|
class _OutputFormatAction(_AccessLinterObjectAction):
|
|
|
|
"""Callback action for setting the output format."""
|
|
|
|
|
|
|
|
def __call__(
|
|
|
|
self,
|
|
|
|
parser: argparse.ArgumentParser,
|
|
|
|
namespace: argparse.Namespace,
|
|
|
|
values: Union[str, Sequence[Any], None],
|
|
|
|
option_string: Optional[str] = "--enable",
|
|
|
|
) -> None:
|
|
|
|
assert isinstance(values, (tuple, list))
|
|
|
|
assert isinstance(
|
|
|
|
values[0], str
|
|
|
|
), "'output-format' should be a comma separated string of reporters"
|
|
|
|
self.linter._load_reporters(values[0])
|