import argparse
from abc import ABC, abstractmethod # pylint: disable=[no-name-in-module]
from pathlib import Path
-from typing import Dict, List, Optional, Tuple, Type, TypeVar
+from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar
from urllib.parse import quote
from knot_resolver.constants import API_SOCK_FILE, CONFIG_FILE
_registered_commands: List[Type["Command"]] = []
+def get_subparsers_words(subparser_actions: List[argparse.Action]) -> CompWords:
+ words: CompWords = {}
+ for action in subparser_actions:
+ if isinstance(action, argparse._SubParsersAction) and action.choices:
+ for choice, parser in action.choices.items():
+ words[choice] = parser.description
+ else:
+ for opt in action.option_strings:
+ words[opt] = action.help
+ return words
+
+
+def get_subparser_by_name(name: str, parser_actions: List[argparse.Action]) -> Optional[argparse.ArgumentParser]:
+ for action in parser_actions:
+ if isinstance(action, argparse._SubParsersAction):
+ if action.choices and name in action.choices:
+ return action.choices[name]
+ return None
+
+
+def get_subparser_command(subparser: argparse.ArgumentParser) -> "Command":
+ defaults: Dict[str, Any] = subparser._defaults
+ if "command" in defaults:
+ return defaults["command"]
+ raise ValueError(f"missing 'command' default for '{subparser.prog}' parser")
+
+
def register_command(cls: T) -> T:
_registered_commands.append(cls)
return cls
from enum import Enum
from typing import Any, Dict, List, Optional, Tuple, Type
-from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command
+from knot_resolver.client.command import Command, CommandArgs, CompWords, get_subparsers_words, register_command
from knot_resolver.datamodel.cache_schema import CacheClearRPCSchema
from knot_resolver.utils.modeling.exceptions import AggregateDataValidationError, DataValidationError
from knot_resolver.utils.modeling.parsing import DataFormat, parse_json
from knot_resolver.utils.requests import request
-from argparse import _SubParsersAction
class CacheOperations(Enum):
@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
- words = dict()
- for action in parser._actions:
- if isinstance(action, _SubParsersAction):
- if action.choices is not None:
- for choice in action.choices:
- words[choice] = action.choices.get(choice)
- else:
- for opt in action.option_strings:
- words[opt] = action.help
- return words
+ return get_subparsers_words(parser._actions)
def run(self, args: CommandArgs) -> None:
if not self.operation:
from enum import Enum
from typing import List, Tuple, Type
-from knot_resolver.client.command import Command, CommandArgs, CompWords, register_command
-from argparse import _SubParsersAction
+from knot_resolver.client.command import (
+ Command,
+ CommandArgs,
+ CompWords,
+ get_subparser_by_name,
+ get_subparser_command,
+ get_subparsers_words,
+ register_command,
+)
class Shells(Enum):
FISH = 1
-def parser_words(actions):
- words = dict()
- for action in actions:
- if isinstance(action, _SubParsersAction):
- if action.choices is not None:
- for choice in action.choices:
- words[choice] = action.choices.get(choice)
- else:
- for opt in action.option_strings:
- words[opt] = action.help
-
- return words
-
-
-def subparser_by_name(uarg: str, actions) -> argparse.ArgumentParser | None:
- for action in actions:
- if isinstance(action, _SubParsersAction):
- if action.choices is not None:
- for choice in action.choices:
- # if uarg == choice:
- if uarg in choice:
- return action.choices.get(choice)
- return None
-
-
-def subparser_command(subparser: argparse.ArgumentParser) -> Command:
- com_class: Command | None = subparser._defaults.get("command")
- # NOTE: This is just a temporary bandage to silence pyright
- assert(com_class is not None)
- return com_class
-
-
@register_command
class CompletionCommand(Command):
def __init__(self, namespace: argparse.Namespace) -> None:
def register_args_subparser(
subparser: "argparse._SubParsersAction[argparse.ArgumentParser]",
) -> Tuple[argparse.ArgumentParser, "Type[Command]"]:
- completion = subparser.add_parser("completion", help="commands auto-completion")
+ completion = subparser.add_parser(
+ "completion",
+ help="commands auto-completion",
+ )
completion.add_argument(
"--space",
help="space after last word, returns all possible folowing options",
@staticmethod
def completion(args: List[str], parser: argparse.ArgumentParser) -> CompWords:
- words: CompWords = {}
- # for action in parser._actions:
- # for opt in action.option_strings:
- # words[opt] = action.help
- # return words
- return words
+ return get_subparsers_words(parser._actions)
def run(self, args: CommandArgs) -> None:
subparsers = args.parser._subparsers
words: CompWords = {}
if subparsers:
- words = parser_words(subparsers._actions)
+ words = get_subparsers_words(subparsers._actions)
uargs = iter(self.comp_args)
- # skip kresctl
- next(uargs)
for uarg in uargs:
- subparser = subparser_by_name(uarg, subparsers._actions) # pylint: disable=W0212
+ subparser = get_subparser_by_name(uarg, subparsers._actions) # pylint: disable=W0212
if subparser:
- cmd: Command = subparser_command(subparser)
+ cmd: Command = get_subparser_command(subparser)
subparser_args = self.comp_args[self.comp_args.index(uarg) + 1 :]
- if subparser_args:
+ if subparser_args or self.space:
words = cmd.completion(subparser_args, subparser)
break
- elif uarg in ["-s", "--socket"]:
+ elif uarg in ["-s", "--socket", "-c", "--config"]:
# if arg is socket config, skip next arg
next(uargs)
continue
elif uarg in words:
- # uarg is walid arg, continue
+ # uarg is valid arg, continue
continue
else:
raise ValueError(f"unknown argument: {uarg}")