Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mutually exclusive group #422

Merged
merged 12 commits into from
Aug 16, 2024
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Version 0.53.4
-------------

This release contains changes from [PR #422](https://github.com/codemagic-ci-cd/cli-tools/pull/422).

**Development**
- Add support for mutually exclusive groups on argument parser.
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved


Version 0.53.3
-------------

Expand Down
52 changes: 43 additions & 9 deletions src/codemagic/cli/argument/argument_parser_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from argparse import _SubParsersAction as SubParsersAction

from codemagic.cli.argument import ActionCallable
from codemagic.cli.argument.argument_properties import MutuallyExclusiveGroup
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved
from codemagic.cli.cli_app import CliApp


Expand Down Expand Up @@ -112,7 +113,7 @@ def set_default_cli_options(cls, cli_options_parser):
verbose=False,
)

def _get_custom_argument_group(self, group_name) -> ArgumentGroup:
def _get_custom_argument_group(self, group_name: str) -> ArgumentGroup:
try:
argument_group = self._custom_arguments_groups[group_name]
except KeyError:
Expand All @@ -123,16 +124,42 @@ def _get_custom_argument_group(self, group_name) -> ArgumentGroup:
self._custom_arguments_groups[group_name] = argument_group
return argument_group

def _get_custom_mutually_exclusive_group(
self,
mutually_exclusive_group: MutuallyExclusiveGroup,
) -> ArgumentGroup:
try:
argument_group = self._custom_arguments_groups[mutually_exclusive_group.group_name]
except KeyError:
group_description = Colors.UNDERLINE(
f"Following arguments are mutually exclusive for {Colors.BOLD(self._cli_action.action_name)}",
)
group = self._action_parser.add_argument_group(group_description)
argument_group = group.add_mutually_exclusive_group(required=mutually_exclusive_group.required)
self._custom_arguments_groups[mutually_exclusive_group.group_name] = argument_group
return argument_group
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved

def _get_argument_group(self, argument) -> ArgumentGroup:
if argument.argument_group_name is None:
if argument.is_required():
argument_group = self._required_arguments
else:
argument_group = self._optional_arguments
else:
if argument.argument_group_name:
argument_group = self._get_custom_argument_group(argument.argument_group_name)
elif argument.mutually_exclusive_group:
argument_group = self._get_custom_mutually_exclusive_group(argument.mutually_exclusive_group)
elif argument.is_required():
argument_group = self._required_arguments
else:
argument_group = self._optional_arguments

return argument_group

def _setup_cli_app_mutually_exclusive_groups(self) -> Dict[str, ArgumentGroup]:
required_groups = {}
for argument in self._cli_app.CLASS_ARGUMENTS:
if argument.mutually_exclusive_group:
mutually_exclusive_group = argument.mutually_exclusive_group
group_name = mutually_exclusive_group.group_name
required_groups[group_name] = self._get_custom_mutually_exclusive_group(mutually_exclusive_group)
return required_groups
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved

def _setup_cli_app_options(self):
executable = self._action_parser.prog.split()[0]
tool_required_arguments = self._action_parser.add_argument_group(
Expand All @@ -141,9 +168,16 @@ def _setup_cli_app_options(self):
tool_optional_arguments = self._action_parser.add_argument_group(
Colors.UNDERLINE(f"Optional arguments for {Colors.BOLD(executable)}"),
)
tool_mutually_exclusive_group = self._setup_cli_app_mutually_exclusive_groups()
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved

for argument in self._cli_app.CLASS_ARGUMENTS:
argument_group = tool_required_arguments if argument.is_required() else tool_optional_arguments
argument.register(argument_group)
group_name = argument.mutually_exclusive_group.group_name if argument.mutually_exclusive_group else None
if group_name:
argument.register(tool_mutually_exclusive_group[group_name])
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved
elif argument.is_required():
argument.register(tool_required_arguments)
else:
argument.register(tool_optional_arguments)

def build(self) -> argparse.ArgumentParser:
self.set_default_cli_options(self._action_parser)
Expand Down
6 changes: 6 additions & 0 deletions src/codemagic/cli/argument/argument_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@
from typing import Union


class MutuallyExclusiveGroup(NamedTuple):
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved
group_name: str
fran-tirapu marked this conversation as resolved.
Show resolved Hide resolved
required: bool


class ArgumentProperties(NamedTuple):
key: str
description: str
type: Union[Type, Callable[[str], Any]] = str
flags: Tuple[str, ...] = tuple()
argparse_kwargs: Optional[Dict[str, Any]] = None
argument_group_name: Optional[str] = None
mutually_exclusive_group: Optional[MutuallyExclusiveGroup] = None

@classmethod
def duplicate(cls, template: Union[Tuple, ArgumentProperties], **overwrites) -> ArgumentProperties:
Expand Down
Loading