_frontend: Fix shell completion with Click >= 8.2
diff --git a/src/buildstream/_frontend/cli.py b/src/buildstream/_frontend/cli.py
index 9d7619b..4f916df 100644
--- a/src/buildstream/_frontend/cli.py
+++ b/src/buildstream/_frontend/cli.py
@@ -15,6 +15,7 @@
import re
import sys
from functools import partial
+from typing import TYPE_CHECKING
import shutil
import click
@@ -25,6 +26,15 @@
from .._remotespec import RemoteSpec, RemoteSpecPurpose
from ..utils import UtilError
+if TYPE_CHECKING or click.Command.__bases__ == (object,):
+ # Click >= 8.2
+ ClickCommandBaseClass = click.Command
+ ClickGroupBaseClass = click.Group
+else:
+ # Click < 8.2
+ ClickCommandBaseClass = click.BaseCommand
+ ClickGroupBaseClass = click.MultiCommand
+
##################################################################
# Helper classes and methods for Click #
@@ -105,7 +115,7 @@
# Completion for completing command names as help arguments
def complete_commands(cmd, args, incomplete):
command_ctx = search_command(args[1:])
- if command_ctx and command_ctx.command and isinstance(command_ctx.command, click.MultiCommand):
+ if command_ctx and command_ctx.command and isinstance(command_ctx.command, ClickGroupBaseClass):
return [
subcommand + " "
for subcommand in command_ctx.command.list_commands(command_ctx)
@@ -272,10 +282,10 @@
original_main(self, args=args, prog_name=prog_name, complete_var=None, standalone_mode=standalone_mode, **extra)
-original_main = click.BaseCommand.main
+original_main = ClickCommandBaseClass.main
# Disable type checking since mypy doesn't support assigning to a method.
# See https://github.com/python/mypy/issues/2427.
-click.BaseCommand.main = override_main # type: ignore
+ClickCommandBaseClass.main = override_main # type: ignore
##################################################################
@@ -392,7 +402,7 @@
click.echo(command_ctx.command.get_help(command_ctx), err=True)
# Hint about available sub commands
- if isinstance(command_ctx.command, click.MultiCommand):
+ if isinstance(command_ctx.command, ClickGroupBaseClass):
detail = " "
if command:
detail = " {} ".format(" ".join(command))
diff --git a/src/buildstream/_frontend/complete.py b/src/buildstream/_frontend/complete.py
index 6fef9d2..787db6d 100644
--- a/src/buildstream/_frontend/complete.py
+++ b/src/buildstream/_frontend/complete.py
@@ -32,11 +32,19 @@
import collections.abc
import copy
import os
+from typing import TYPE_CHECKING
import click
-from click.core import MultiCommand, Option, Argument
+from click.core import Option, Argument
from click.parser import split_arg_string
+if TYPE_CHECKING or click.Command.__bases__ == (object,):
+ # Click >= 8.2
+ ClickGroupBaseClass = click.Group
+else:
+ # Click < 8.2
+ ClickGroupBaseClass = click.MultiCommand
+
WORDBREAK = "="
COMPLETION_SCRIPT = """
@@ -176,7 +184,7 @@
ctx = cli.make_context(prog_name, args, resilient_parsing=True)
args_remaining = ctx.protected_args + ctx.args
while ctx is not None and args_remaining:
- if isinstance(ctx.command, MultiCommand):
+ if isinstance(ctx.command, ClickGroupBaseClass):
cmd = ctx.command.get_command(ctx, args_remaining[0])
if cmd is None:
return None
@@ -310,7 +318,7 @@
found_param = True
break
- if not found_param and isinstance(ctx.command, MultiCommand):
+ if not found_param and isinstance(ctx.command, ClickGroupBaseClass):
# completion for any subcommands
choices.extend(
[cmd + " " for cmd in ctx.command.list_commands(ctx) if not ctx.command.get_command(ctx, cmd).hidden]
@@ -319,7 +327,7 @@
if (
not start_of_option(incomplete)
and ctx.parent is not None
- and isinstance(ctx.parent.command, MultiCommand)
+ and isinstance(ctx.parent.command, ClickGroupBaseClass)
and ctx.parent.command.chain
):
# completion for chained commands