如何为单击处理的参数列表指定默认值?

时间:2019-05-28 23:19:54

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

我有这行代码,可以捕获传递给我的Python脚本的所有文件名:

@click.argument("logs", nargs=-1, type=click.File('r'), required=1)

当没有传递文件名时,我想默认为-,即标准输入。所以,如果我尝试:

@click.argument("logs", nargs=-1, type=click.File('r'), required=1, default="-")

点击变得不满意并引发此错误:

  

TypeError:不支持将nargs = -1与默认值结合使用。

是否有解决方法?我尝试设置nargs=0,但这会引发另一个错误:

  

IndexError:元组索引超出范围

3 个答案:

答案 0 :(得分:2)

要默认将stdin用于可能为空的文件列表,可以定义一个自定义参数类,例如:

自定义类别:

class FilesDefaultToStdin(click.Argument):
    def __init__(self, *args, **kwargs):
        kwargs['nargs'] = -1
        kwargs['type'] = click.File('r')
        super().__init__(*args, **kwargs)

    def full_process_value(self, ctx, value):
        return super().process_value(ctx, value or ('-', ))

将此行为定义为类可提供方便的重用。

要使用自定义类:

@click.command()
@click.argument("logs", cls=FilesDefaultToStdin)
def main(logs):
    ...

这是如何工作的?

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

在这种情况下,我们将覆盖click.Argument.full_process_value()。在我们的full_process_value()中,查找一个空的参数列表,如果为空,则将-(stdin)参数添加到列表中。

此外,我们自动分配nargs=-1type=click.File('r')参数。

答案 1 :(得分:1)

由于click明确表示他们禁用了问题所需的特定功能(如this issue在其项目中的报道),因此需要一种解决方法,并且可以轻松地将其实施为Python函数(而不是其他答案的注释所建议的,更多的是bash代码)。

解决方法是简单地删除必需的参数并使用一条语句处理丢失的日志(类似于this commit所做的引用链接问题的操作):

import sys
import click

@click.command()
@click.argument("logs", nargs=-1, type=click.File('r'))
def main(logs):
    if not logs:
        logs = (sys.stdin,)
    print(logs)
    # do stuff with logs

if __name__ == '__main__': 
    main()

执行示例

$ python fail.py 
(<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,)
$ python fail.py -
(<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>,)
$ python fail.py foo bar
(<_io.TextIOWrapper name='foo' mode='r' encoding='UTF-8'>, <_io.TextIOWrapper name='bar' mode='r' encoding='UTF-8'>)

答案 2 :(得分:0)

以下代码:

import click


@click.command()
@click.option('--logs', '-l', multiple=True, default='-')
def cli(logs):
    click.echo('\n'.join(logs))

将产生以下内容:

$ myhello -l foo.log -l bar.log -l baz.log
foo.log
bar.log
baz.log
$ myhello
-

因此,如果您只是可以使用重复的参数以不同的方式调用程序,那将是您所需要的解决方法。