Взаимоисключающие группы опций в python Click

Как я могу создать взаимоисключающую группу опций в Click? Я хочу либо принять флаг «--all», либо выбрать опцию с параметром, например «--color red».


person b-jazz    schedule 18.05.2016    source источник
comment
Не похоже. Разве вы не можете просто создать опцию all, а затем вызывать все остальные функции из этой опции?   -  person Charlie    schedule 19.05.2016
comment
@Charlie: да, но тогда пользователь может указать --all --color red в командной строке, и это кажется неправильным.   -  person b-jazz    schedule 19.05.2016
comment
Хорошо - расскажи мне больше. Что должно произойти, если они это сделают? Может быть, вы могли бы написать пример кода.   -  person Charlie    schedule 19.05.2016


Ответы (3)


Недавно я столкнулся с этим же вариантом использования; это то, что я придумал. Для каждого варианта можно дать список конфликтующих вариантов.

from click import command, option, Option, UsageError


class MutuallyExclusiveOption(Option):
    def __init__(self, *args, **kwargs):
        self.mutually_exclusive = set(kwargs.pop('mutually_exclusive', []))
        help = kwargs.get('help', '')
        if self.mutually_exclusive:
            ex_str = ', '.join(self.mutually_exclusive)
            kwargs['help'] = help + (
                ' NOTE: This argument is mutually exclusive with '
                ' arguments: [' + ex_str + '].'
            )
        super(MutuallyExclusiveOption, self).__init__(*args, **kwargs)

    def handle_parse_result(self, ctx, opts, args):
        if self.mutually_exclusive.intersection(opts) and self.name in opts:
            raise UsageError(
                "Illegal usage: `{}` is mutually exclusive with "
                "arguments `{}`.".format(
                    self.name,
                    ', '.join(self.mutually_exclusive)
                )
            )

        return super(MutuallyExclusiveOption, self).handle_parse_result(
            ctx,
            opts,
            args
        )

Затем используйте обычный декоратор option, но передайте аргумент cls:

@command(help="Run the command.")
@option('--jar-file', cls=MutuallyExclusiveOption,
        help="The jar file the topology lives in.",
        mutually_exclusive=["other_arg"])
@option('--other-arg',
        cls=MutuallyExclusiveOption,
        help="The jar file the topology lives in.",
        mutually_exclusive=["jar_file"])
def cli(jar_file, other_arg):
    print "Running cli."
    print "jar-file: {}".format(jar_file)
    print "other-arg: {}".format(other_arg)

if __name__ == '__main__':
    cli() 

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

Если это не сработает для вас, есть несколько (закрытых) проблем, упоминающих об этом на странице click github с парой идей, которые вы можете использовать.

person Jacob    schedule 27.05.2016


Вы можете использовать Cloup, пакет, который добавляет группы опций и ограничения в Click. У вас есть два варианта решения этой проблемы в Cloup.

Отказ от ответственности: я являюсь автором пакета.

Вариант 1: @option_group

Когда вы определяете группу параметров с помощью @option_group, параметры каждой группы отображаются в отдельных разделах справки (например, в argparse). Вы можете применять ограничения (например, mutually_exclusive) к группам опций следующим образом:

from cloup import command, option, option_group
from cloup.constraints import mutually_exclusive

@command()
@option_group(
    'Color options',
    option('--all', 'all_colors', is_flag=True),
    option('--color'),
    constraint=mutually_exclusive
)
def cmd(**kwargs):
    print(kwargs)

Помощь будет:

Usage: cmd [OPTIONS]

Color options [mutually exclusive]:
  --all       
  --color TEXT

Other options:
  --help        Show this message and exit.

Вариант 2: @ограничение

Если вы не хотите, чтобы группы параметров отображались в справке по команде, вы можете использовать @constraint и указать ограниченные параметры по их (целевому) имени:

from cloup import command, option
from cloup.constraints import constraint, mutually_exclusive

@command()
@option('--all', 'all_colors', is_flag=True)
@option('--color')
@constraint(mutually_exclusive, ['all_colors', 'color'])
def cmd(**kwargs):
    print(kwargs)

Определенные таким образом ограничения можно задокументировать в справке по команде! Эта функция отключена по умолчанию, но ее можно легко включить, передав show_constraints=True в @command. Результат:

Usage: cmd [OPTIONS]

Options:
  --all       
  --color TEXT
  --help        Show this message and exit.

Constraints:
  {--all, --color}  mutually exclusive

Сообщение об ошибке

В обоих случаях, если вы запустите cmd --all --color red, вы получите:

Usage: cmd [OPTIONS]
Try 'cmd --help' for help.

Error: the following parameters are mutually exclusive:
  --all 
  --color

Другие ограничения

Cloup определяет ограничения, которые должны покрывать 99,9% ваших потребностей. Он даже поддерживает условные ограничения!

Например, если пользователь должен предоставить один из ваших взаимоисключающих вариантов, замените mutually_exclusive на RequireExactly(1) в приведенном выше примере.

Все доступные ограничения можно найти здесь.

person janluke    schedule 10.02.2021