python - 如何创建在整数旁边显示选项并允许使用整数输入选择选项的命令行提示符?

标签 python command-line command-line-interface command-line-arguments python-click

如何使用click编写命令行提示符,如下所示:

choose name:
[1] Karen
[2] Bob
[3] Jo
[4] Steve

并调用一个函数,例如:

def print_function(name):
    if name == 'Karen':
        print('CEO')
    elif name == 'Bob':
        print('CFO')
    elif name == 'Jo':
        print('COO')
    elif name == 'Steve':
        print('CIO')
    else:
        raise ValueError('Wrong name')

总而言之,如何创建一个显示用户选项并允许他们输入整数以选择与这些选项对应的命令提示符?

此外,如果从命令行调用函数时使用了 --name Bob,如何使命令提示符可选?

最佳答案

使用继承自 click.Option 的自定义类,您可以拦截选项处理并显示所需的菜单,然后像这样验证响应:

自定义类

import click

class EnumMenuPromptFromDict(click.Option):

    def __init__(self, *args, **kwargs):
        super(EnumMenuPromptFromDict, self).__init__(*args, **kwargs)
        if 'prompt' not in kwargs:
            raise TypeError(
                "'prompt' keyword required for '{}' option".format(
                    args[0][0]))

        self.choices_dict = self.prompt
        self.prompt_menu = '\n'.join('[{}] {}'.format(i + 1, name)
                                     for i, name in enumerate(self.prompt))
        self.prompt = 'Choose from,\n{}\n{}'.format(
            self.prompt_menu, self.name)

    def prompt_for_value(self, ctx):
        """Get entered value and then validate"""
        while True:
            value = super(EnumMenuPromptFromDict, self).prompt_for_value(ctx)
            try:
                choice = int(value)
                if choice > 0:
                    return list(self.choices_dict)[choice - 1]
            except (ValueError, IndexError):
                if value in self.choices_dict:
                    return value
            click.echo('Error: {} is not a valid choice'.format(value))

    def full_process_value(self, ctx, value):
        """Convert the entered value to the value from the choices dict"""
        value = super(EnumMenuPromptFromDict, self).full_process_value(
            ctx, value)
        try:
            return self.choices_dict[value]
        except (KeyError, IndexError):
            raise click.UsageError(
                "'{}' is not a valid choice".format(value), ctx)

使用自定义类:

要使用自定义类,请将 cls 参数传递给 @click.option() 装饰器,例如:

@click.option('--name', cls=EnumMenuPromptFromDict, prompt=titles)

prompt 是一个选项的字典,例如:

titles = OrderedDict((
    ('Karen', 'CEO'),
    ('Bob', 'CFO'),
    ('Jo', 'COO'),
    ('Steve', 'CIO')
))

这是如何运作的?

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

在这种情况下,我们越过 click.Option.prompt_for_value() 来拦截命令处理并允许输入菜单编号或值。我们还覆盖了 click.Option.full_process_value() 以将名称转换为标题。

测试代码:

from collections import OrderedDict
titles = OrderedDict((
    ('Karen', 'CEO'),
    ('Bob', 'CFO'),
    ('Jo', 'COO'),
    ('Steve', 'CIO')
))

@click.command()
@click.option('--name', cls=EnumMenuPromptFromDict, prompt=titles)
def cli(name):
    """The Great CLI APP"""
    click.echo('a title: %s' % name)

if __name__ == "__main__":
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    cli([])

关于python - 如何创建在整数旁边显示选项并允许使用整数输入选择选项的命令行提示符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49186376/

相关文章:

python - 用于删除 XML 注释和 HTML 元素的 Python 中的正则表达式

windows - 从命令行列出所有环境变量

php - 使用增量配置启动 PHP

php - 如何检查 PHP CURL SSL 是否有效

jdbc - 有没有成熟的命令行 JDBC 客户端?

python - 在哪里使用 ipython 和 ipthon shell 在哪里?

python - Flask-RESTful 我们可以在资源中 get 和 post 之前调用一个方法吗?

regex - 执行大型正则表达式操作的最佳方法是什么?

command-line - VSCode : list enabled extensions in a particular workspace in Commandline

python - 在 Python/Django : MPTT alternative? 中存储分层(父/子)数据