如何将多个参数列表传递给@click.option
How to pass several list of arguments to @click.option
我想用这种参数通过命令行调用一个python脚本(列表可以是任何大小,例如3):
python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
使用点击。从文档中,没有任何地方说明我们可以使用列表作为 @click.option
的参数
当我尝试这样做时:
#!/usr/bin/env python
import click
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', default=[])
def do_stuff(option):
return
# do stuff
if __name__ == '__main__':
do_stuff()
在我的 test.py
中,通过从命令行调用它:
python test.py --option ["some option", "some option 2"]
我收到一个错误:
Error: Got unexpected extra argument (some option 2])
我不能真正使用可变参数,因为每个命令只允许 1 个可变参数 (http://click.pocoo.org/5/arguments/#variadic-arguments)
因此,如果有人能指出正确的方向(最好使用点击),我将不胜感激。
如果使用自定义选项 class 将列表格式化为 python 列表的字符串文字,则您可以强制点击获取多个列表参数,例如:
自定义 Class:
import click
import ast
class PythonLiteralOption(click.Option):
def type_cast_value(self, ctx, value):
try:
return ast.literal_eval(value)
except:
raise click.BadParameter(value)
此 class 将使用 Python 的 Abstract Syntax Tree 模块将参数解析为 python 文字。
自定义Class用法:
要使用自定义 class,请将 cls
参数传递给 @click.option()
装饰器,例如:
@click.option('--option1', cls=PythonLiteralOption, default=[])
这是如何工作的?
之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.option()
装饰器通常实例化一个 click.Option
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 中继承 click.Option
并覆盖所需的方法是一件相对容易的事情。
在这种情况下,我们超越 click.Option.type_cast_value()
,然后调用 ast.literal_eval()
来解析列表。
测试代码:
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option1', cls=PythonLiteralOption, default=[])
@click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
click.echo("Option 1, type: {} value: {}".format(
type(option1), option1))
click.echo("Option 2, type: {} value: {}".format(
type(option2), option2))
# do stuff
if __name__ == '__main__':
import shlex
cli(shlex.split(
'''--option1 '["o11", "o12", "o13"]'
--option2 '["o21", "o22", "o23"]' '''))
测试结果:
Option 1, type: <type 'list'> value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'> value: ['o21', 'o22', 'o23']
以下可能是更简单的黑客修复:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
except ValueError:
pass
# do stuff
if __name__ == '__main__':
do_stuff()
这可以帮助您将 'option' 用作 list
或 str
。
@Murphy 的 "easy hack" 几乎对我有用,但问题是 option
将是 string
除非你单引号选项,所以我必须按顺序执行此操作重组列表:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
# option = str(option) # this also works
except ValueError:
pass
option = option[1:-1] # trim '[' and ']'
options = option.split(',')
for i, value in enumerate(options):
# catch integers
try:
int(value)
except ValueError:
options[i] = value
else:
options[i] = int(value)
# Here use options as you need
# do stuff
if __name__ == '__main__':
do_stuff()
你可以捕捉到一些其他类型
要使用它,请将列表括在引号中:
python test.py --option "[o11, o12, o13]"
或者您可以通过不留空格来避免引号:
python test.py --option [o11,o12,o13]
如果您不坚持传递看起来像列表的东西,而只是想传递多个可变参数,您可以使用 multiple
选项。
@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
click.echo('\n'.join(message))
$ commit -m foo -m bar
foo
bar
Stephen Rauch 的回答让我在使用 Kubernetes 参数时遇到了一些问题。这是因为字符串格式变得很麻烦,并且经常在数组前后添加新行、单引号或空格。因此,我制作了自己的解析器来改进这种行为。
这段代码应该是不言自明的。
请注意,此代码不支持变量本身中的单引号或双引号 '
或 "
。
自定义 class:
class ConvertStrToList(click.Option):
def type_cast_value(self, ctx, value) -> List:
try:
value = str(value)
assert value.count('[') == 1 and value.count(']') == 1
list_as_str = value.replace('"', "'").split('[')[1].split(']')[0]
list_of_items = [item.strip().strip("'") for item in list_as_str.split(',')]
return list_of_items
except Exception:
raise click.BadParameter(value)
自定义 class 用法:
@click.option('--option1', cls=ConvertStrToList, default=[])
我想用这种参数通过命令行调用一个python脚本(列表可以是任何大小,例如3):
python test.py --option1 ["o11", "o12", "o13"] --option2 ["o21", "o22", "o23"]
使用点击。从文档中,没有任何地方说明我们可以使用列表作为 @click.option
的参数当我尝试这样做时:
#!/usr/bin/env python
import click
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', default=[])
def do_stuff(option):
return
# do stuff
if __name__ == '__main__':
do_stuff()
在我的 test.py
中,通过从命令行调用它:
python test.py --option ["some option", "some option 2"]
我收到一个错误:
Error: Got unexpected extra argument (some option 2])
我不能真正使用可变参数,因为每个命令只允许 1 个可变参数 (http://click.pocoo.org/5/arguments/#variadic-arguments)
因此,如果有人能指出正确的方向(最好使用点击),我将不胜感激。
如果使用自定义选项 class 将列表格式化为 python 列表的字符串文字,则您可以强制点击获取多个列表参数,例如:
自定义 Class:
import click
import ast
class PythonLiteralOption(click.Option):
def type_cast_value(self, ctx, value):
try:
return ast.literal_eval(value)
except:
raise click.BadParameter(value)
此 class 将使用 Python 的 Abstract Syntax Tree 模块将参数解析为 python 文字。
自定义Class用法:
要使用自定义 class,请将 cls
参数传递给 @click.option()
装饰器,例如:
@click.option('--option1', cls=PythonLiteralOption, default=[])
这是如何工作的?
之所以可行,是因为 click 是一个设计良好的 OO 框架。 @click.option()
装饰器通常实例化一个 click.Option
对象,但允许使用 cls
参数覆盖此行为。因此,在我们自己的 class 中继承 click.Option
并覆盖所需的方法是一件相对容易的事情。
在这种情况下,我们超越 click.Option.type_cast_value()
,然后调用 ast.literal_eval()
来解析列表。
测试代码:
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option1', cls=PythonLiteralOption, default=[])
@click.option('--option2', cls=PythonLiteralOption, default=[])
def cli(option1, option2):
click.echo("Option 1, type: {} value: {}".format(
type(option1), option1))
click.echo("Option 2, type: {} value: {}".format(
type(option2), option2))
# do stuff
if __name__ == '__main__':
import shlex
cli(shlex.split(
'''--option1 '["o11", "o12", "o13"]'
--option2 '["o21", "o22", "o23"]' '''))
测试结果:
Option 1, type: <type 'list'> value: ['o11', 'o12', 'o13']
Option 2, type: <type 'list'> value: ['o21', 'o22', 'o23']
以下可能是更简单的黑客修复:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
except ValueError:
pass
# do stuff
if __name__ == '__main__':
do_stuff()
这可以帮助您将 'option' 用作 list
或 str
。
@Murphy 的 "easy hack" 几乎对我有用,但问题是 option
将是 string
除非你单引号选项,所以我必须按顺序执行此操作重组列表:
#!/usr/bin/env python
import click
import json
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--option', help='Whatever')
def do_stuff(option):
try:
option = json.loads(option)
# option = str(option) # this also works
except ValueError:
pass
option = option[1:-1] # trim '[' and ']'
options = option.split(',')
for i, value in enumerate(options):
# catch integers
try:
int(value)
except ValueError:
options[i] = value
else:
options[i] = int(value)
# Here use options as you need
# do stuff
if __name__ == '__main__':
do_stuff()
你可以捕捉到一些其他类型
要使用它,请将列表括在引号中:
python test.py --option "[o11, o12, o13]"
或者您可以通过不留空格来避免引号:
python test.py --option [o11,o12,o13]
如果您不坚持传递看起来像列表的东西,而只是想传递多个可变参数,您可以使用 multiple
选项。
@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
click.echo('\n'.join(message))
$ commit -m foo -m bar
foo
bar
Stephen Rauch 的回答让我在使用 Kubernetes 参数时遇到了一些问题。这是因为字符串格式变得很麻烦,并且经常在数组前后添加新行、单引号或空格。因此,我制作了自己的解析器来改进这种行为。
这段代码应该是不言自明的。
请注意,此代码不支持变量本身中的单引号或双引号 '
或 "
。
自定义 class:
class ConvertStrToList(click.Option):
def type_cast_value(self, ctx, value) -> List:
try:
value = str(value)
assert value.count('[') == 1 and value.count(']') == 1
list_as_str = value.replace('"', "'").split('[')[1].split(']')[0]
list_of_items = [item.strip().strip("'") for item in list_as_str.split(',')]
return list_of_items
except Exception:
raise click.BadParameter(value)
自定义 class 用法:
@click.option('--option1', cls=ConvertStrToList, default=[])