单击-基于其他选项的提示动态默认值

时间:2018-08-14 17:12:44

标签: python python-click

我正在使用Click构建CLI界面。点击优惠dynamic defaults for prompts,非常好。 this example还提供了一些有关如何使用自定义点击类实现动态默认值的见解,从而在评估默认值时提供了更灵活的选项。

我现在想要做的是根据另一个提供的点击选项(例如,

)设置动态默认设置。
python mymodule --param1 something --param2 somethingelse

现在,如果param2为空,我想尝试根据提供的param1输入获得动态默认值,例如:

@click.command()
@click.option('--param1', prompt=True)
@click.option('--param2', prompt=True, default=lambda: myfunct(param1))
def cmd(param1, param2):
    pass

myfunct(param1:str=None):
    param2 = None
    #get param2 based on param1 input
    return param2

关于什么是最好的方法的任何想法? 并保证在param1之前对param2进行评估(并提示输入)吗?

1 个答案:

答案 0 :(得分:2)

扩展example you referenced可以实现所需的功能,例如:

自定义类别:

import click

class OptionPromptNull(click.Option):
    _value_key = '_default_val'

    def __init__(self, *args, **kwargs):
        self.default_option = kwargs.pop('default_option', None)
        super(OptionPromptNull, self).__init__(*args, **kwargs)

    def get_default(self, ctx):
        if not hasattr(self, self._value_key):
            if self.default_option is None:
                default = super(OptionPromptNull, self).get_default(ctx)
            else:
                arg = ctx.params[self.default_option]
                default = self.type_cast_value(ctx, self.default(arg))
            setattr(self, self._value_key, default)
        return getattr(self, self._value_key)

    def prompt_for_value(self, ctx):
        default = self.get_default(ctx)

        # only prompt if the default value is None
        if default is None:
            return super(OptionPromptNull, self).prompt_for_value(ctx)

        return default

使用自定义类:

要使用自定义类,您需要将三个参数传递给click.option装饰器,例如:

@click.option('--param3', cls=OptionPromptNull, default_option='param1',
              default=lambda x: get_a_value(x), prompt="Enter Param3")
  • cls需要引用自定义类。

  • default_option需要指定将哪个选项传递给default可调用对象。

  • default指定用于获取默认值的可调用对象。

这是如何工作的?

之所以可行,是因为click是一个设计良好的OO框架。 @click.option()装饰器通常会实例化click.Option对象,但允许使用cls参数来覆盖此行为。因此,在我们自己的类中继承click.Option并超越所需的方法是相对容易的事情。

在这种情况下,我们过度使用click.Option.get_default()click.Option.prompt_for_value()方法。在prompt_for_value()中,我们仅提示默认值为None。然后在get_default()中,我们调用default函数,以传递所需的(先前输入的)参数。

为澄清问题的一部分,首先评估选项:按在命令行中传递的顺序,然后评估:对未在命令行中传递的选项的声明顺序。 / p>

测试代码:

@click.command()
@click.option('--param1', prompt="Enter Param1")
@click.option('--param2', cls=OptionPromptNull,
              default=lambda: get_value_none(), prompt="Enter Param2")
@click.option('--param3', cls=OptionPromptNull, default_option='param1',
              default=lambda x: get_a_value(x), prompt="Enter Param3")
def cli(param1, param2, param3):
    click.echo("param1: '{}'".format(param1))
    click.echo("param2: '{}'".format(param2))
    click.echo("param3: '{}'".format(param3))


def get_value_none():
    return None

def get_a_value(val):
    return val

if __name__ == "__main__":
    commands = (
        r'',
        r'--param3 5',
        '--help',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            cli(cmd.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)]
-----------
> 
Enter Param1: 3
Enter Param2: 4
param1: '3'
param2: '4'
param3: '3'
-----------
> --param3 5
Enter Param1: 3
Enter Param2: 4
param1: '3'
param2: '4'
param3: '5'
-----------
> --help
Usage: test.py [OPTIONS]

Options:
  --param1 TEXT
  --param2 TEXT
  --param3 TEXT
  --help         Show this message and exit.