如何为点击处理的参数列表指定默认值?
How to specify a default value for argument list processed by 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 in combination with a default value is not supported.
有解决办法吗?我尝试设置 nargs=0
但会引发不同的错误:
IndexError: tuple index out of range
以下代码:
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
-
因此,如果您可以使用重复的参数以不同的方式调用您的程序,那将是您正在寻找的解决方法。
由于 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'>)
要将可能为空的文件列表默认为 stdin
,您可以定义一个自定义参数 class,例如:
自定义 Class:
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 ('-', ))
将此行为定义为 class 便于重用。
要使用自定义 Class:
@click.command()
@click.argument("logs", cls=FilesDefaultToStdin)
def main(logs):
...
这是如何工作的?
之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.argument()
装饰器通常实例化一个 click.Argument
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 和 over-ride 中继承 click.Argument
所需的方法是一件相对容易的事情。
在这种情况下,我们覆盖 click.Argument.full_process_value()
。在我们的 full_process_value()
中,我们寻找一个空的参数列表,如果为空,我们将 -
(stdin) 参数添加到列表中。
此外,我们自动分配 nargs=-1
和 type=click.File('r')
参数。
我有这行代码,预计会获取传递给我的 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 in combination with a default value is not supported.
有解决办法吗?我尝试设置 nargs=0
但会引发不同的错误:
IndexError: tuple index out of range
以下代码:
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
-
因此,如果您可以使用重复的参数以不同的方式调用您的程序,那将是您正在寻找的解决方法。
由于 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'>)
要将可能为空的文件列表默认为 stdin
,您可以定义一个自定义参数 class,例如:
自定义 Class:
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 ('-', ))
将此行为定义为 class 便于重用。
要使用自定义 Class:
@click.command()
@click.argument("logs", cls=FilesDefaultToStdin)
def main(logs):
...
这是如何工作的?
之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.argument()
装饰器通常实例化一个 click.Argument
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 和 over-ride 中继承 click.Argument
所需的方法是一件相对容易的事情。
在这种情况下,我们覆盖 click.Argument.full_process_value()
。在我们的 full_process_value()
中,我们寻找一个空的参数列表,如果为空,我们将 -
(stdin) 参数添加到列表中。
此外,我们自动分配 nargs=-1
和 type=click.File('r')
参数。