使用 Python Click 扩展 BASH 完成

Sco*_*oks 4 command-line-interface bash-completion python-click

我想自定义我的 Python Click CLI 程序的 BASH 完成功能,不仅包括脚本的命令/子命令,还包括脚本创建的对象。

假设我的程序被调用cli-tool,它可以foo使用以下命令创建对象:

cli-tool object create foo
Run Code Online (Sandbox Code Playgroud)

为简单起见,假设该命令只是将参数字符串(foo在本例中)连接到位于~/.cli-tool/objects/foo. 这样做cat ~/.cli-tool/objects/foo,然后将打印foo在你的终端。

我希望该工具做的是当我输入:

cli-tool object get <TAB><TAB>
Run Code Online (Sandbox Code Playgroud)

终端然后将名单foo及任何其他文件里面住~/.cli-tool/objects。

作为记录,我已阅读Python Click 6.x stable 文档,其中明确指出:

目前,Bash 补全是一个不可定制的内部功能。这在未来的版本中可能会放宽。

我希望有一种方法可以从以下命令中提取完整的BASH 完成脚本:

eval "$(_CLI_TOOL_COMPLETE=source cli-tool)"
Run Code Online (Sandbox Code Playgroud)

然后自己定制。我也看过点击完成项目,但我不确定它除了扩展 Zsh 和 Fish shell 的完成之外还有什么作用。

有没有人达到我上面提到的完成类型?

Ste*_*uch 5

使用click-completion,这是非常简单的。

代码:

导入并init()点击完成:

import click
import click_completion

click_completion.init()
Run Code Online (Sandbox Code Playgroud)

然后实例化一个click.Choice对象:

option_type = click.Choice('obj1 obj2 obj3'.split())
Run Code Online (Sandbox Code Playgroud)

对于您的选项目录,请传入适当项目的列表,而不是示例obj1-obj3。

然后将选项类型传递给click.argument()装饰器,如:

@click.argument('option', type=option_type)
Run Code Online (Sandbox Code Playgroud)

并且不要忘记使用您的外壳激活您的完成。bash 的点击变化在这里:

测试代码:

import click
import click_completion

click_completion.init()

option_type = click.Choice('obj1 obj2 obj3'.split())

@click.group()
def cli():
    """My Cool Tool"""

@cli.group(name='object')
def object_group():
    """Object subcommand"""

@object_group.command()
@click.argument('option', type=option_type)
def get(option):
    click.echo('option: {}'.format(option))


commands = (
    ('"" object get ""', 1),
    ('"" object get ""', 2),
    ('"" object get ""', 3),
    'object get obj1',
    '--help',
    'object --help',
    'object get --help',
)

os.environ['BASH_COMP'] = 'complete'

import sys, time
time.sleep(1)
print('Click Version: {}'.format(click.__version__))
print('Click Completion Version: {}'.format(click_completion.__version__))
print('Python Version: {}'.format(sys.version))
for cmd in commands:
    try:
        time.sleep(0.1)
        print('\n-----------')
        print('> ' + str(cmd))
        time.sleep(0.1)

        if len(cmd) == 2:
            os.environ['COMP_WORDS'] = cmd[0]
            os.environ['COMP_CWORD'] = str(cmd[1])
            cli(complete_var='BASH_COMP')
        else:
            try:
                del os.environ['COMP_WORDS']
                del os.environ['COMP_CWORD']
            except:
                pass
            cli(cmd.split())


    except BaseException as exc:
        if str(exc) != '0' and \
                not isinstance(exc, (click.ClickException, SystemExit)):
            raise
Run Code Online (Sandbox Code Playgroud)

结果:

Click Version: 6.7
Click Completion Version: 0.4.1
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]

-----------
> ('"" object get ""', 1)
object
-----------
> ('"" object get ""', 2)
get
-----------
> ('"" object get ""', 3)
obj1    obj2    obj3
-----------
> object get obj1
option: obj1

-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  My Cool Tool

Options:
  --help  Show this message and exit.

Commands:
  object  Object subcommand

-----------
> object --help
Usage: test.py object [OPTIONS] COMMAND [ARGS]...

  Object subcommand

Options:
  --help  Show this message and exit.

Commands:
  get

-----------
> object get --help
Usage: test.py object get [OPTIONS] OPTION

Options:
  --help  Show this message and exit.
Run Code Online (Sandbox Code Playgroud)