Skip to content

Commit

Permalink
python: client: completion: not to sugest already used args and alter…
Browse files Browse the repository at this point in the history
…natives to them
  • Loading branch information
alesmrazek committed Dec 19, 2024
1 parent 894c3ce commit cb46ae2
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 68 deletions.
97 changes: 41 additions & 56 deletions python/knot_resolver/client/command.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import argparse
from abc import ABC, abstractmethod # pylint: disable=[no-name-in-module]
from abc import ABC, abstractmethod
from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple, Type, TypeVar
from urllib.parse import quote
Expand All @@ -21,43 +21,17 @@
_registered_commands: List[Type["Command"]] = []


def get_mutually_exclusive_commands(parser: argparse.ArgumentParser) -> List[Set[str]]:
command_names: List[Set[str]] = []
def get_mutually_exclusive_args(parser: argparse.ArgumentParser) -> List[Set[str]]:
groups: List[Set[str]] = []

for group in parser._mutually_exclusive_groups: # noqa: SLF001
command_names.append(set())
group_args: Set[str] = set()
for action in group._group_actions: # noqa: SLF001
if action.option_strings:
command_names[-1].update(action.option_strings)
return command_names


def is_unique_and_new(arg: str, args: Set[str], exclusive: List[Set[str]], last: str) -> bool:
if arg not in args:
for excl in exclusive:
if arg in excl:
for cmd in excl:
if cmd in args:
return False
return True

return arg == last


def get_subparsers_words(
subparser_actions: List[argparse.Action], args: Set[str], exclusive: List[Set[str]], last: str
) -> CompWords:
words: CompWords = {}
for action in subparser_actions:
if isinstance(action, argparse._SubParsersAction) and action.choices: # noqa: SLF001
for choice, parser in action.choices.items():
if is_unique_and_new(choice, args, exclusive, last):
words[choice] = parser.description
else:
for opt in action.option_strings:
if is_unique_and_new(opt, args, exclusive, last):
words[opt] = action.help

return words
group_args.update(action.option_strings)
if group_args:
groups.append(group_args)
return groups


def get_parser_action(name: str, parser_actions: List[argparse.Action]) -> Optional[argparse.Action]:
Expand Down Expand Up @@ -91,24 +65,34 @@ def comp_get_actions_words(parser_actions: List[argparse.Action]) -> CompWords:
return words


def comp_get_words(args: List[str], parser_actions: List[argparse.Action]) -> CompWords: # noqa: PLR0912
words: CompWords = comp_get_actions_words(parser_actions)
def comp_get_words(args: List[str], parser: argparse.ArgumentParser) -> CompWords: # noqa: PLR0912
words: CompWords = comp_get_actions_words(parser._actions) # noqa: SLF001
nargs = len(args)

skip_arg = False
for i, arg in enumerate(args):
action: Optional[argparse.Action] = get_parser_action(arg, parser_actions) # noqa: SLF001
action: Optional[argparse.Action] = get_parser_action(arg, parser._actions) # noqa: SLF001

if skip_arg:
skip_arg = False
continue

if not action:
words = comp_get_actions_words(parser_actions)
continue

if i + 1 >= nargs:
return words
continue

# remove exclusive arguments from words
for exclusive_args in get_mutually_exclusive_args(parser):
if arg in exclusive_args:
for earg in exclusive_args:
if earg in words.keys():
del words[earg]
# remove alternative arguments from words
for opt in action.option_strings:
if opt in words.keys():
del words[opt]

# if not action or action is HelpAction or VersionAction
if isinstance(action, (argparse._HelpAction, argparse._VersionAction)): # noqa: SLF001
Expand All @@ -121,27 +105,28 @@ def comp_get_words(args: List[str], parser_actions: List[argparse.Action]) -> Co

# if action is StoreAction
if isinstance(action, argparse._StoreAction): # noqa: SLF001
choices = {}
if action.choices:
for choice in action.choices:
choices[choice] = action.help
else:
choices[COMP_DIRNAMES] = None
choices[COMP_FILENAMES] = None
words = choices
if i + 2 >= nargs:
choices = {}
if action.choices:
for choice in action.choices:
choices[choice] = action.help
else:
choices[COMP_DIRNAMES] = None
choices[COMP_FILENAMES] = None
words = choices
skip_arg = True
continue

# if action is SubParserAction
if isinstance(action, argparse._SubParsersAction): # noqa: SLF001
subparser = action.choices[arg]
cmd = get_subparser_command(subparser)
return cmd.completion(args[i + 1 :], subparser) if cmd else {}

# delete already used args
for arg in args:
if arg in words.keys():
del words[arg]
subparser: Optional[argparse.ArgumentParser] = action.choices[arg] if arg in action.choices else None

command = get_subparser_command(subparser) if subparser else None
if command and subparser:
return command.completion(args[i + 1 :], subparser)
if subparser:
return comp_get_words(args[i + 1 :], subparser) # noqa: SLF001
return {}

return words

Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
if not self.operation:
Expand Down
8 changes: 4 additions & 4 deletions python/knot_resolver/client/commands/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None: # noqa: PLR0912
words: CompWords = {}

subparsers = args.parser._subparsers # noqa: SLF001
if subparsers:
words = comp_get_words(self.args, subparsers._actions) # noqa: SLF001
parser = args.parser
if parser:
words = comp_get_words(self.args, args.parser)

# print completion words
# based on required bash/fish shell format
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:

return words

return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
if not self.operation:
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
with open(self.input_file, "r") as f:
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None: # noqa: PLR0912, PLR0915
if self.gdb is None:
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def run(self, args: CommandArgs) -> None:

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

@staticmethod
def register_args_subparser(
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
response = request(args.socket, "GET", "metrics/prometheus" if self.prometheus else "metrics/json")
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
if self.live:
Expand Down
2 changes: 1 addition & 1 deletion python/knot_resolver/client/commands/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def register_args_subparser(

@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
return comp_get_words(args, parser._actions) # noqa: SLF001
return comp_get_words(args, parser)

def run(self, args: CommandArgs) -> None:
if self.input_file:
Expand Down

0 comments on commit cb46ae2

Please sign in to comment.