Python Click: NoSuchOption exception when manually attaching Option objects to Command instance using

。_饼干妹妹 提交于 2020-03-04 05:03:48

问题


My code sample:

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)

What I'm trying to achieve is to be able to dynamically create different options for a given command depending on the value of an eager flag option to the same command using the click library.

When I execute the above command on the CLI as $ python cli_test.py, this is printed to stdout {'standardize': False, 'extra_opts': {}}, as expected. Similarly $ python cli_test.py -S prints {'standardize': True, 'extra_opts': {}}, also expected.

And when I invoke the built-in --help option with $ python cli_test.py --help, I get:

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.

Which seems to suggest that the attachment of the --no-standardize specific option via the std_cb callback for the -S flag is working as well.

Similarly, $ python cli_test.py --help -S, produces:

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.

Now with the -a option appearing due to the presence of the -S flag.

However, if I were to try and do $ python cli_test.py -b hello, I'd get the error: click.exceptions.NoSuchOption: no such option: -b.

And similarly, $ python cli_test.py -S -a world produces click.exceptions.NoSuchOption: no such option: -a, despite them showing up in the help page under their applicable -S flag value.

What I had expected to see from the given code example is of course, $ python cli_test.py -b hello printing {'standardize': True, 'extra_opts': {'b': 'hello'}}.

And $ python cli_test.py -S -a world printing {'standardize': True, 'extra_opts': {'a': 'world'}}.

In the Click docs, the authors do state that using @click.option "is equivalent to creating an Option instance manually and attaching it to the Command.params list.", so I'm not really sure what I'm doing wrong.


回答1:


I'm not sure if your code should work, but I wonder if you could live with something like I've sketched here:

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)

This seems to me to produce the same results (except extra_opts always includes both a and b, but with the values of None if not set). A benefit, from my point of view is that the documentation always documents both a and b. As a user, I assume I would want that.



来源:https://stackoverflow.com/questions/60469503/python-click-nosuchoption-exception-when-manually-attaching-option-objects-to-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!