]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
python: client: completion: not to sugest already used args and alternatives to them
authorAleš Mrázek <ales.mrazek@nic.cz>
Thu, 19 Dec 2024 23:33:49 +0000 (00:33 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 20 Dec 2024 21:24:22 +0000 (22:24 +0100)
python/knot_resolver/client/command.py
python/knot_resolver/client/commands/cache.py
python/knot_resolver/client/commands/completion.py
python/knot_resolver/client/commands/config.py
python/knot_resolver/client/commands/convert.py
python/knot_resolver/client/commands/debug.py
python/knot_resolver/client/commands/help.py
python/knot_resolver/client/commands/metrics.py
python/knot_resolver/client/commands/schema.py
python/knot_resolver/client/commands/validate.py

index 79dd9bec21c3b074e959fbf5439a55f02c52c237..3966f8ca93663b58cbe619cb665f982d3158471a 100644 (file)
@@ -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
@@ -21,43 +21,17 @@ COMP_NOSPACE = "#nospace#"
 _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]:
@@ -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
@@ -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
 
index 66ee77c96c4eee576e22eca3f18d2a209eca31fe..a1bebeedc7365a1b5e95761fe29a0a39682460ee 100644 (file)
@@ -99,7 +99,7 @@ class CacheCommand(Command):
 
     @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:
index 75f8e1eb0980cb07b56090cd3223160377f3b4b9..5e3d36288ec583331f721ea816fea49e272f8c71 100644 (file)
@@ -45,14 +45,14 @@ class CompletionCommand(Command):
 
     @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
index fef3ad79cb5c3f78dab3d306cae2986c1c8db882..69f7edfa2c39e825964589b7e398a61447d2f5a4 100644 (file)
@@ -158,7 +158,7 @@ class ConfigCommand(Command):
 
             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:
index 28a5be957e3d513f68a36b23f9afb187f8f0a3ee..aab07519cb5a5203cf80c37350c2b6c1d202b9c0 100644 (file)
@@ -50,7 +50,7 @@ class ConvertCommand(Command):
 
     @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:
index 71ce673edb3e3635505fc42578f8f14ec1770d83..14341e9d4b3574e62f2dbc9a2483ecfa5b33095c 100644 (file)
@@ -61,7 +61,7 @@ class DebugCommand(Command):
 
     @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:
index 1db83fb6106f6b4ae540f4e246b99a9fd9bf735a..949420911f53172a08ff3d24653d3d72148ddbb0 100644 (file)
@@ -14,7 +14,7 @@ class HelpCommand(Command):
 
     @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(
index eaf83090dfe9e5f2f62f89a55002a7a09930dff2..57ff917197820617a8e2b58911b0784f00dd33e1 100644 (file)
@@ -44,7 +44,7 @@ class MetricsCommand(Command):
 
     @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")
index fdb65bdee49eedfa06693bb66078ffe580720e69..c5e4dfc4448199a7f46a04a5ff141cd43334722b 100644 (file)
@@ -35,7 +35,7 @@ class SchemaCommand(Command):
 
     @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:
index 2347519ee6dfb8f9a0f3963e4474a910e3e92e4a..92848b5848e738bf380c0ecd10109c9e9f784280 100644 (file)
@@ -41,7 +41,7 @@ class ValidateCommand(Command):
 
     @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: