Нажмите группу с параметрами и командами одновременно

Я пытаюсь создать приложение со следующим поведением:

myapp - запустит приложение и сделает что-то А

myapp "some argument" - сделал бы вещь B. На вещь B влияет аргумент "какой-то аргумент".

myapp command — запустит «команду» (обозначается декоратором @cli.command) с функцией C. На это будут влиять все, что может предложить щелчок, например @click.option.

Обратите внимание, что в моем приложении будет больше команд, таких как C.


Я попытался реализовать это, используя этот код:

import click

class GroupWithOption(click.Group):
    def list_commands(self, ctx):
        return ['command']

    def get_command(self, ctx, cmd_name):
        if cmd_name == 'command':
            return command
        else:
            return do_b


@click.group(cls=GroupWithOption, invoke_without_command=True)
def main():
    print("Does A")

@main.command()
def command():
    print("Does C")

@main.command()
def do_b():
    print("Does B")


if __name__ == '__main__':
    main()

Это имело смешанные результаты. Во-первых, я могу очень легко вызвать 3 разных поведения (или более), но я не смог понять, как передать аргумент команде B. Мне не нравится это решение. Оно не кажется чистым. И для правильной работы потребуется использование глобальных переменных и некоторые неприятные хаки.

Кто-нибудь из вас знает о лучшем способе, как это сделать?


person tomascapek    schedule 26.02.2019    source источник
comment
Как вы думаете, что это должно делать: if cmd_name == 'command': return command ?   -  person Stephen Rauch    schedule 27.02.2019
comment
Если я вас правильно понял - класс GroupWithOption используется для разрешения всех возможных команд. Но мне приходится делать это вручную. Надеюсь, я правильно понял документацию и get_command действительно должен вернуть функцию, которая обрабатывает данную подкоманду.   -  person tomascapek    schedule 27.02.2019
comment
Я все еще в замешательстве. Это правильно?: Никакой аргумент не делает A, если первый аргумент соответствует команде, выполните эту команду, то есть: C, все остальное делает B.   -  person Stephen Rauch    schedule 27.02.2019
comment
Да, это правильно.   -  person tomascapek    schedule 27.02.2019


Ответы (1)


Один из способов сделать это — объединить два ответа, приведенных здесь:

Ключевые элементы:

@click.group(cls=DefaultCommandGroup, invoke_without_command=True)
@click.pass_context
def main(ctx):
    if not ctx.invoked_subcommand:
        click.echo("Does A")

@main.command(default_command=True)
@click.argument('args', nargs=-1)
def default_cmd_with_args(args):
    click.echo("Does B: {}".format(args))

Как это работает?

if not ctx.invoked_subcommand:

Позволяет вызывать групповую команду только в случае отсутствия команды, а

@click.group(cls=DefaultCommandGroup, invoke_without_command=True)

в сочетании с:

@main.command(default_command=True)

позволяет выполнить команду, если не найдена другая команда.

Тестовый код:

import click

@click.group(cls=DefaultCommandGroup, invoke_without_command=True)
@click.pass_context
def main(ctx):
    """My Great CLI"""
    if not ctx.invoked_subcommand:
        click.echo("Does A")

@main.command(default_command=True)
@click.argument('args', nargs=-1)
def default_cmd_with_args(args):
    """Command run without a command"""
    click.echo("Does B: {}".format(args))


@main.command()
def cmd_c1():
    """A c1 command"""
    click.echo("Does C1")


@main.command()
def cmd_c2():
    """A c2 command"""
    click.echo("Does C2")


if __name__ == "__main__":
    commands = (
        '',
        'random args',
        'cmd_c1',
        'cmd_c2',
        '--help',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for command in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + command)
            time.sleep(0.1)
            main(command.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

Полученные результаты:

Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> 
Does A
-----------
> random args
Does B: ('random', 'args')
-----------
> cmd_c1
Does C1
-----------
> cmd_c2
Does C2
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  My Great CLI

Options:
  --help  Show this message and exit.

Commands:
  <>      Command run without a command
  cmd_c1  A c1 command
  cmd_c2  A c2 command
person Stephen Rauch    schedule 28.02.2019