Skip to content

Commit

Permalink
Create _ExtendArgument
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielNoord committed Apr 14, 2022
1 parent 85a4804 commit c5a5e18
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 3 deletions.
49 changes: 47 additions & 2 deletions pylint/config/argument.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@

from pylint import interfaces
from pylint import utils as pylint_utils
from pylint.config.callback_actions import _CallbackAction
from pylint.config.callback_actions import _CallbackAction, _ExtendAction
from pylint.config.deprecation_actions import _NewNamesAction, _OldNamesAction
from pylint.constants import PY38_PLUS

if sys.version_info >= (3, 8):
from typing import Literal
Expand Down Expand Up @@ -294,7 +295,7 @@ def __init__(
self,
*,
flags: List[str],
action: Type[argparse._StoreAction],
action: Type[argparse.Action],
default: _ArgumentTypes,
arg_type: str,
choices: Optional[List[str]],
Expand Down Expand Up @@ -330,6 +331,50 @@ def __init__(
"""


class _ExtendArgument(_DeprecationArgument):
"""Class for extend arguments to be parsed by an argparse.ArgumentsParser.
This is based on the parameters passed to argparse.ArgumentsParser.add_message.
See:
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument
"""

def __init__(
self,
*,
flags: List[str],
action: Literal["extend"],
default: _ArgumentTypes,
arg_type: str,
metavar: str,
arg_help: str,
hide_help: bool,
section: Optional[str],
choices: Optional[List[str]],
dest: Optional[str],
) -> None:
# The extend action is included in the stdlib from 3.8+
if PY38_PLUS:
action_class = argparse._ExtendAction # type: ignore[attr-defined]
else:
action_class = _ExtendAction

self.dest = dest
"""The destination of the argument."""

super().__init__(
flags=flags,
action=action_class,
default=default,
arg_type=arg_type,
choices=choices,
arg_help=arg_help,
metavar=metavar,
hide_help=hide_help,
section=section,
)


class _StoreOldNamesArgument(_DeprecationArgument):
"""Store arguments while also handling old names.
Expand Down
12 changes: 12 additions & 0 deletions pylint/config/arguments_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pylint.config.argument import (
_Argument,
_CallableArgument,
_ExtendArgument,
_StoreArgument,
_StoreNewNamesArgument,
_StoreOldNamesArgument,
Expand Down Expand Up @@ -191,6 +192,17 @@ def _add_parser_option(
action=argument.action,
help=argument.help,
)
elif isinstance(argument, _ExtendArgument):
section_group.add_argument(
*argument.flags,
action=argument.action,
default=argument.default,
type=argument.type, # type: ignore[arg-type] # incorrect typing in typeshed
help=argument.help,
metavar=argument.metavar,
choices=argument.choices,
dest=argument.dest,
)
else:
raise UnrecognizedArgumentAction

Expand Down
12 changes: 12 additions & 0 deletions pylint/config/arguments_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ def set_option(self, optname, value, action=None, optdict=None):
setattr(self.config, optname, _list + (value,))
else:
_list.append(value)
elif action == "extend":
_list = getattr(self.config, optname, None)
if _list is None:
if isinstance(value, (list, tuple)):
_list = value
elif value is not None:
_list = [value]
setattr(self.config, optname, _list)
elif isinstance(_list, tuple):
setattr(self.config, optname, _list + (value,))
else:
_list.extend(value)
elif (
action == "callback"
or (not isinstance(action, str))
Expand Down
21 changes: 21 additions & 0 deletions pylint/config/callback_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,27 @@ def __call__(
return None


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)


class _AccessRunObjectAction(_CallbackAction):
"""Action that has access to the Run object."""

Expand Down
16 changes: 15 additions & 1 deletion pylint/config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pylint import extensions, utils
from pylint.config.argument import (
_CallableArgument,
_ExtendArgument,
_StoreArgument,
_StoreNewNamesArgument,
_StoreOldNamesArgument,
Expand All @@ -33,6 +34,7 @@ def _convert_option_to_argument(
_CallableArgument,
_StoreOldNamesArgument,
_StoreNewNamesArgument,
_ExtendArgument,
]:
"""Convert an optdict to an Argument class instance."""
if "level" in optdict and "hide" not in optdict:
Expand Down Expand Up @@ -84,7 +86,19 @@ def _convert_option_to_argument(
DeprecationWarning,
)
default = None

if action == "extend":
return _ExtendArgument(
flags=flags,
action=action,
default=default,
arg_type=optdict["type"],
choices=choices,
arg_help=optdict.get("help", ""),
metavar=optdict.get("metavar", ""),
hide_help=optdict.get("hide", False),
section=optdict.get("group", None),
dest=optdict.get("dest", None),
)
if "kwargs" in optdict:
if "old_names" in optdict["kwargs"]:
return _StoreOldNamesArgument(
Expand Down

0 comments on commit c5a5e18

Please sign in to comment.