【问题标题】:Click - Dynamic Defaults for Prompts based on other options单击 - 基于其他选项的提示的动态默认值
【发布时间】:2018-08-14 17:12:44
【问题描述】:

我正在使用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

对于完成此任务的最佳方法有什么想法吗? 是否保证在param2 之前评估(并提示)param1?

【问题讨论】:

    标签: python python-click


    【解决方案1】:

    扩展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 函数传递所需的(之前输入的)参数。

    为了澄清问题的一部分,首先评估选项:按照它们在命令行中传递的顺序,其次:按照它们为那些未在命令行中传递的选项声明的顺序。

    测试代码:

    @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.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-14
      • 2019-08-25
      • 2019-12-12
      • 2021-10-14
      相关资源
      最近更新 更多