Python 点击 (str, str) 选项的自动完成
Python Click autocomplete for (str, str) option
我正在使用 Python 和 Click 编写 CLI 工具。其中一个命令有一个 type=(str, str))
选项,用法如下:command subcommand --option foo bar
.
第一个参数 (foo) 有多个选项可供选择,对于第一个参数的每个选择,第二个参数 (bar) 也有多个选项可供选择。所以第二个参数的选项取决于第一个参数的选择!
问题是:如何使用 support that Click 提供的功能为此编写自动完成功能?
特别是:
- 我是否需要两个完成函数,每个参数一个?
- 第二个函数如何提供第一个参数的选择?
- 如何为单个选项定义两个补全函数?
- 或者,我可以对两个参数使用一个函数吗?那会是什么样子?
要自动完成包含两个字符串的点击选项,其中第二个字符串取决于第一个字符串,您不需要两个完成函数。您只需要一种方法来确定当前正在完成两个字符串中的哪一个。对于名为 --opt
的选项,我们可以完成一种 (str, str)
类型,例如:
代码:
def get_opts(ctx, args, incomplete):
""" auto complete for option "opt"
:param ctx: The current click context.
:param args: The list of arguments passed in.
:param incomplete: The partial word that is being completed, as a
string. May be an empty string '' if no characters have
been entered yet.
:return: list of possible choices
"""
opts = {
'foo1': ('bar11', 'bar21', 'bar31'),
'foo2': ('bar12', 'bar22', 'bar32'),
'fox3': ('bar13', 'bar23', 'bar33'),
}
if args[-1] == '--opt':
possible_choices = opts.keys()
elif args[-1] in opts:
possible_choices = opts[args[-1]]
else:
possible_choices = ()
return [arg for arg in possible_choices if arg.startswith(incomplete)]
使用自动完成
可以通过autocompletion
函数点赞:
@click.option('--opt', type=(str, str), autocompletion=get_opts)
这是如何工作的?
autocompletion
函数被传递给 args
的列表。当完成一个选项时,我们可以在args
中找到我们的选项名称。在这种情况下,我们可以在 args 中查找 --opt
以获得我们是完成第一个字符串还是第二个字符串的位置的锚点。然后我们 return 匹配已输入字符的字符串。
测试代码:
import click
@click.command()
@click.option('--opt', type=(str, str), autocompletion=get_opts)
@click.argument('arg')
def cli(opt, arg):
"""My Great Cli"""
if __name__ == "__main__":
commands = (
('--opt', 2, 'foo1 foo2 fox3'),
('--opt f', 2, 'foo1 foo2 fox3'),
('--opt fo', 2, 'foo1 foo2 fox3'),
('--opt foo', 2, 'foo1 foo2'),
('--opt fox', 2, 'fox3'),
('--opt foz', 2, ''),
('--opt foo2 b', 3, 'bar12 bar22 bar32'),
('--opt foo2 bar1', 3, 'bar12'),
('--opt foo2 baz', 3, ''),
)
import os
import sys
from unittest import mock
from click._bashcomplete import do_complete
failed = []
for cmd_args in commands:
cmd_args_with_arg = (
'arg ' + cmd_args[0], cmd_args[1] + 1, cmd_args[2])
for cmd in (cmd_args, cmd_args_with_arg):
with mock.patch('click._bashcomplete.echo') as echo:
os.environ['COMP_WORDS'] = 'x ' + cmd[0]
os.environ['COMP_CWORD'] = str(cmd[1])
do_complete(cli, 'x', False)
completions = [c[0][0] for c in echo.call_args_list]
if completions != cmd[2].split():
failed.append(completions, cmd[2].split())
print('Click Version: {}'.format(click.__version__))
print('Python Version: {}'.format(sys.version))
if failed:
for fail in failed:
print('Got {}, expected {}'.format(completions, cmd[2].split()))
else:
print('All tests passed')
测试结果:
Click Version: 7.0
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
All tests passed
我正在使用 Python 和 Click 编写 CLI 工具。其中一个命令有一个 type=(str, str))
选项,用法如下:command subcommand --option foo bar
.
第一个参数 (foo) 有多个选项可供选择,对于第一个参数的每个选择,第二个参数 (bar) 也有多个选项可供选择。所以第二个参数的选项取决于第一个参数的选择!
问题是:如何使用 support that Click 提供的功能为此编写自动完成功能?
特别是:
- 我是否需要两个完成函数,每个参数一个?
- 第二个函数如何提供第一个参数的选择?
- 如何为单个选项定义两个补全函数?
- 或者,我可以对两个参数使用一个函数吗?那会是什么样子?
要自动完成包含两个字符串的点击选项,其中第二个字符串取决于第一个字符串,您不需要两个完成函数。您只需要一种方法来确定当前正在完成两个字符串中的哪一个。对于名为 --opt
的选项,我们可以完成一种 (str, str)
类型,例如:
代码:
def get_opts(ctx, args, incomplete):
""" auto complete for option "opt"
:param ctx: The current click context.
:param args: The list of arguments passed in.
:param incomplete: The partial word that is being completed, as a
string. May be an empty string '' if no characters have
been entered yet.
:return: list of possible choices
"""
opts = {
'foo1': ('bar11', 'bar21', 'bar31'),
'foo2': ('bar12', 'bar22', 'bar32'),
'fox3': ('bar13', 'bar23', 'bar33'),
}
if args[-1] == '--opt':
possible_choices = opts.keys()
elif args[-1] in opts:
possible_choices = opts[args[-1]]
else:
possible_choices = ()
return [arg for arg in possible_choices if arg.startswith(incomplete)]
使用自动完成
可以通过autocompletion
函数点赞:
@click.option('--opt', type=(str, str), autocompletion=get_opts)
这是如何工作的?
autocompletion
函数被传递给 args
的列表。当完成一个选项时,我们可以在args
中找到我们的选项名称。在这种情况下,我们可以在 args 中查找 --opt
以获得我们是完成第一个字符串还是第二个字符串的位置的锚点。然后我们 return 匹配已输入字符的字符串。
测试代码:
import click
@click.command()
@click.option('--opt', type=(str, str), autocompletion=get_opts)
@click.argument('arg')
def cli(opt, arg):
"""My Great Cli"""
if __name__ == "__main__":
commands = (
('--opt', 2, 'foo1 foo2 fox3'),
('--opt f', 2, 'foo1 foo2 fox3'),
('--opt fo', 2, 'foo1 foo2 fox3'),
('--opt foo', 2, 'foo1 foo2'),
('--opt fox', 2, 'fox3'),
('--opt foz', 2, ''),
('--opt foo2 b', 3, 'bar12 bar22 bar32'),
('--opt foo2 bar1', 3, 'bar12'),
('--opt foo2 baz', 3, ''),
)
import os
import sys
from unittest import mock
from click._bashcomplete import do_complete
failed = []
for cmd_args in commands:
cmd_args_with_arg = (
'arg ' + cmd_args[0], cmd_args[1] + 1, cmd_args[2])
for cmd in (cmd_args, cmd_args_with_arg):
with mock.patch('click._bashcomplete.echo') as echo:
os.environ['COMP_WORDS'] = 'x ' + cmd[0]
os.environ['COMP_CWORD'] = str(cmd[1])
do_complete(cli, 'x', False)
completions = [c[0][0] for c in echo.call_args_list]
if completions != cmd[2].split():
failed.append(completions, cmd[2].split())
print('Click Version: {}'.format(click.__version__))
print('Python Version: {}'.format(sys.version))
if failed:
for fail in failed:
print('Got {}, expected {}'.format(completions, cmd[2].split()))
else:
print('All tests passed')
测试结果:
Click Version: 7.0
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
All tests passed