Python Click: исключение NoSuchOption при ручном присоединении объектов Option к экземпляру Command с помощью - PullRequest
1 голос
/ 29 февраля 2020

Пример моего кода:

import click


def std_cb(ctx, param, standardize):
    if standardize:
        opt = click.Option(param_decls=['-a'],
                           help='this option only exists when -S is set')
    else:
        opt = click.Option(param_decls=['-b'],
                           help='this option only exists when -S is not set')
    ctx.command.params.append(opt)
    return standardize


@click.command()
@click.option('-S', '--standardize/--no-standardize', is_eager=True,
              is_flag=True, default=False, callback=std_cb)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)

То, чего я пытаюсь добиться, - это возможность динамически создавать различные параметры для данной команды в зависимости от значения опции флага eager для той же команды, используя библиотека щелчков.

Когда я выполняю указанную выше команду для CLI как $ python cli_test.py, она выводится на стандартный вывод {'standardize': False, 'extra_opts': {}}, как и ожидалось. Точно так же $ python cli_test.py -S печатает {'standardize': True, 'extra_opts': {}}, также ожидается.

И когда я вызываю встроенную опцию --help с $ python cli_test.py --help, я получаю:

Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -b TEXT                         this option only exists when -S is not set
  --help                          Show this message and exit.

Что, кажется, предположить, что вложение опции --no-standardize speci c через обратный вызов std_cb для флага -S также работает.

Аналогично, $ python cli_test.py --help -S, производит:

Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -a TEXT                         this option only exists when -S is set
  --help                          Show this message and exit.

Теперь с появлением опции -a из-за наличия флага -S.

Однако, если бы я попытался сделать $ python cli_test.py -b hello, я бы получил ошибку: click.exceptions.NoSuchOption: no such option: -b.

И, аналогично, $ python cli_test.py -S -a world производит click.exceptions.NoSuchOption: no such option: -a, несмотря на то, что они отображаются на странице справки под соответствующим значением флага -S.

То, что я ожидал увидеть от приведенный пример кода, конечно, $ python cli_test.py -b hello печать {'standardize': True, 'extra_opts': {'b': 'hello'}}.

и $ python cli_test.py -S -a world печать {'standardize': True, 'extra_opts': {'a': 'world'}}.

В Нажмите документы , авторы Убедитесь, что использование @click.option "эквивалентно созданию экземпляра Option вручную и присоединению его к списку Command.params.", поэтому я не совсем уверен, что делаю неправильно .

1 Ответ

1 голос
/ 01 марта 2020

Я не уверен, что ваш код должен работать, но мне интересно, если бы вы могли жить с чем-то вроде того, что я набросал здесь:

import click


def require_standardize_set(ctx, param, value):                                                                                                                   
    if value and not ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is set'.format(param.name))
    return value

def require_standardize_not_set(ctx, param, value):
    if value and ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is not set'.format(param.name))
    return value


@click.command()
@click.option('-S', '--standardize/--no-standardize',
              is_flag=True, default=False, is_eager=True)
@click.option('-a', help='this option requires that -S is set',
              callback=require_standardize_set)
@click.option('-b', help='this option requires that -S is not set',
              callback=require_standardize_not_set)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)

Мне кажется, это дает те же результаты (кроме extra_opts всегда включает в себя a и b, но со значениями None, если не установлено). С моей точки зрения, выгода в том, что документация всегда документирует как a, так и b. Как пользователь, я предполагаю, что хотел бы этого.

...