命令行接口的声明性解析器

cliglue的Python项目详细描述


cli glue-用于cli的胶水

github版本pypi versiondocumentation status构建状态coverage status

cliglue是python中命令行接口的声明性解析器。 它是cli shell参数和正在调用的函数之间的绑定粘合剂。

cliglue在运行控制台应用程序时解析并验证用户提供的命令行参数。 然后根据声明的命令行接口规则,自动触发匹配的操作,注入所有需要的参数。 您不需要每次都为绑定和解析参数编写"粘合"代码。 因此,它使编写控制台应用程序更快、更简单。

功能

快速启动

让我们使用cliglue创建简单的命令行应用程序。 假设我们已经有了如下函数:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)

我们需要一个"胶水",它与cli(命令行界面)绑定。 我们希望它以用户提供给终端外壳的不同参数运行: /hello.py world--reverse--repeat=1。 我们刚刚确定了一个位置参数、一个标志和一个数值参数。 因此,我们的cli定义可以使用cliglue声明

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)

总而言之,我们用命令行界面绑定了函数:

你好。py

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()

让我们追踪这里发生的事情:

  • clibuilder为整个应用程序生成cli树。
  • 'hello-app'是要在帮助输出中显示的应用程序的名称。
  • run=say_hello设置应用程序的默认操作。现在一个函数say_hello被绑定为一个主操作,如果没有匹配的其他操作,它将被调用。
  • .has(…)允许在该生成器中嵌入其他规则。返回clibuilder本身。
  • 参数('name')声明位置参数。从现在起,第一个cli参数(在二进制名称之后)将被识别为name变量。
  • flag('reverse')--reverse关键字绑定到名为reverse的标志。以便以后使用。
  • 参数('repeat',type=int,default=1)--repeat关键字绑定到名为repeat的参数,该参数的类型为int,其默认值为1
  • 最后,调用.run()完成所有的魔术。 它获取系统参数列表,开始处理它们并调用相关操作。

帮助/用法

clibuilder默认情况下添加了一些基本选项,如--help--version。 因此,您可以使用--help标志运行应用程序来检查使用情况:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 

请注意,已经显示了一些规则,这些规则是以前声明的:

  • 位置参数名称/hello.py[选项]名称
  • 标志倒车--倒车
  • 参数重复--重复

注入参数

现在,当我们使用提供的一个参数执行应用程序时,会得到:

foo@bar:~$ ./hello.py world
Hello world.

注意world已被识别为name参数。 我们将say\u hello绑定为默认操作,因此它已使用特定参数调用:

say_hello(name='world',reverse=False,repeat=1)
  • 位置参数name被分配了一个'world'值。
  • 未给出标志reverse,因此默认情况下为false
  • 参数repeat也未给定,因此将其设置为默认值1

让我们显式地提供所有参数,然后得到:

foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.

或者我们可以用不同的方式来做同样的事情:

foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.

当您正在为操作编写函数,并且需要访问某些变量(标志、参数、参数等)时, 只需在函数中添加一个与所需变量同名的参数。 然后,通过cliglue

它是如何工作的?

  1. 你定义了一切声明树中程序所需的cli规则。
  2. 在shell中运行程序时,用户提供命令行参数。
  3. cliglue解析并验证所有参数、标志、子命令、位置参数等,并在内部存储它们。
  4. cliglue找到最相关的操作(从最具体的开始)并调用它。
  5. 调用函数时,cliglue根据先前定义和分析的值注入它所需的所有参数。

您只需将关键字绑定到规则,然后cliglue将为您处理其余的所有内容。

cligluevsargparse

既然我们已经有了pythonargparse,为什么要使用cliglue?以下是cliglue的一些主观优势:

  • 一个地方的cli逻辑声明方式,
  • 开箱即用的自动完成功能,
  • 构建多级子命令的更简单方法,
  • 自动操作绑定和注入参数,无需手动将参数传递给函数,
  • 与应用程序逻辑分离的cli逻辑,
  • 更简单简洁的cli构建-在读取代码时,更容易区分它们之间的特定cli规则(即位置参数、参数或子命令的标志),
  • 作为清晰文档的cli定义代码。

argparse迁移到cliglue

基本客户端

argparse:

importargparseparser=argparse.ArgumentParser(description='Program description')[herecometherules...]args=parser.parse_args()do_something(args)

剪贴画:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
0

标志

argparse:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
1

剪贴画:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
2

位置参数

argparse:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
3

剪贴画:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
4

子命令

argparse:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
5

剪贴画:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
6

将值传输到函数

argparse:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
7

剪贴画:

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
8

安装

第1步。先决条件

  • python 3.6(或更新版本)

关于Debian 10(Buster)

defsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)
9

在Debian 9上(拉伸)

不幸的是,Debian Stretch发行版的存储库中没有Python3.6+,但是可以从源代码编译它:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
0 在ubuntu 18上
CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
1

在CentOS 7上
CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
2

在软呢帽上
CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
3

第2步。使用pip安装软件包

从使用pip:

的pypi存储库安装包
CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
4

或者使用显式python版本:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
5

以开发模式安装软件包

您可以在开发模式下安装软件包,以便对自己的软件包进行任何更改:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
6

测试

运行测试:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
7

clibuilder

clibuildercliglue包的一个主要类,它允许构建cli定义。 它是一个命令行接口规范的构建器。 之后,您可以调用.run()方法来解析提供的参数并调用特定的操作。

空clibuilder默认情况下启用了标准选项:

  • --help-显示用法和帮助
  • --版本-显示应用程序版本号(如果已定义)

第1步。创建clibuilder

在此步骤中,您可以创建新的clibuilder并为其设置自定义配置。 构造函数如下:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
8

名称-为其生成cli的应用程序的名称

版本-应用程序版本(显示在帮助/版本输出中)

帮助-应用程序的简短说明

运行-函数的引用,该函数应该是空参数列表的默认操作

使用默认值-是否应添加默认规则和操作。 默认选项为: -h,--帮助:显示帮助, --版本:显示版本, --bash install app-name:安装应用程序在bash中自动完成, --bash autocomplete[命令行…]:生成由bash处理的自动完成的建议的内部操作

用法错误-语法错误时应显示用法输出

reraise_error-不应捕获语法错误,而应重新引发语法错误。 启用此选项将导致堆栈跟踪被淹没到用户。

hide_internal-内部选项(--bash install--bash autocomplete)应在帮助输出中隐藏。

第2步。声明cli规则

下一步是使用.has()方法为clibuilder声明cli规则

has(*subrules:clirule)->;'clibuilder'方法在其参数中接收一个cli规则,并返回clibuilder自身以进行进一步的构建。 它用于引入下一级的子规则。

可用规则如下:

  • 子命令
  • 标志
  • 参数
  • 参数
  • 参数
  • 默认操作
  • 主选项

示例:

CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),)
9

第3步。通过解析器运行cli参数

最后一步是调用clibuilder上的.run()。 它解析传递给应用程序的所有cli参数。 然后调用之前定义的触发动作。 如果操作需要一些参数,则将根据解析的参数注入这些参数。

运行空生成器:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
0

只打印标准帮助输出,因为如果没有提供参数,它是空生成器的默认操作。

子命令

命令可以用嵌套的子命令形成多级树。 子命令语法是众所周知的,例如:

  • Git远程重命名…
  • 码头集装箱LS
  • nmcli设备WiFi列表
  • IP地址显示

子命令将cli分成许多嵌套的cli级别,形成一个树。 它们决定将解析器指向何处,解析器寻找要调用的最相关的操作,并决定哪些规则处于活动状态。

子命令创建子解析器的嵌套级别,这些子解析器不仅可能具有不同的操作,而且还包含不同的cli规则,例如命名参数、标志或其他子命令,这些子命令仅在启用父命令时才启用。 子命令可以有更多的子规则,只有当相应的子命令处于活动状态时才会激活这些子规则。 所以子命令只是一个缩小上下文范围的关键字。

子命令规范

要创建子命令规则规范,请使用:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
1

关键字-它们中的任何一个都可能触发子命令的关键字参数

运行-匹配子命令时要调用的可选操作

帮助-帮助输出中显示的参数说明

嵌套子命令

使用子命令,可以嵌套其他cli规则。 只有当相应的子命令处于活动状态时,它们才会处于活动状态。

子规则可以使用嵌套。has(*subrules:clirule)方法。 它返回自身以进行进一步的构建,因此可以像clibuilder

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
2

这样,上面的格式化代码就构成了一个清晰可见的可视树。

子命令示例:sub commands.py

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
3

用法很自我描述:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
4

有关更详细的用例,请参见子命令测试。

标志

flag是一个由单个关键字切换的布尔参数。 支持短格式(-f)和长格式(--force)。

要创建标志规则规范,请使用:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
5

关键字是参数(一个或多个),它们中的任何一个在发生时启用标志。 标志值false。 可以使用直接格式传递标志关键字:-f--flag, 以及按名称:f标志,也将计算为-f--标志。 单字符标志将得到单连字符前缀(-f), 较长的标志名称将得到双连字符前缀(--flag)。

帮助是帮助输出中显示的标志的说明

multiple-是否允许多次出现标志。 然后标志具有int类型并存储其出现次数

示例:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
6

用法:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
7

组合用短标志

许多短标志可以组合在一个参数中。您只需键入-tulpn,而不是-t-u-l-p-n

多次出现标记

标志也支持多次出现。当multiple设置为true时,标志值表示设置了多少次。然后,值类型是int,而不是bool

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
8

那么-vvv应该返回3

有关更详细的用例,请参见标志测试

命名参数

参数是一个命名值,它将按其名称注入已触发的操作。 参数值的设置支持两种方式: --参数名值--参数名=值

命名参数可以出现在cli参数列表中的任何位置:开头或结尾,甚至在位置参数之前。 只要它们作为命名参数匹配,就不会被识别为位置参数。

这些参数以后可以由其名称或关键字引用 (小写格式,不带连字符前缀,带下划线而不是破折号, 例如,--参数名将被注入为参数名

要创建参数规则规范,请使用:

#!/usr/bin/env python3fromcliglueimportCliBuilder,argument,flag,parameterdefsay_hello(name:str,reverse:bool,repeat:int):ifreverse:name=name[::-1]print(f'Hello {name}.'*repeat)CliBuilder('hello-app',run=say_hello).has(argument('name'),flag('reverse'),parameter('repeat',type=int,default=1),).run()
9

关键字与参数匹配的关键字参数。 参数关键字可以使用直接格式传递:-p--param, 以及按名称:pparam,将计算为-p--param。 单字符参数将得到单连字符前缀(-p), 较长的参数名将得到双连字符前缀(--param

name是显式参数名(当它与任何关键字不同时,可以使用)

帮助是帮助输出中显示的参数的说明

必需指示是否需要参数。 如果需要,但没有给出,则会引发语法错误。

默认值是参数的默认值,如果没有给定(并且不是必需的)。

type是一种参数值类型(例如str、int、float)。 这里也可以提供对解析器函数的引用。 然后通过将字符串参数值传递给该函数来计算参数值。

选项是参数值可用选项的显式列表 或引用将被调用以检索此类可能值列表的函数

严格的选项-是否应根据可用选项验证给定参数

multiple-参数是否允许多次出现。 然后参数具有列表类型并存储值列表

基本参数示例:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
0
foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
1

出现多个参数

参数也支持多次出现。 当multiple设置为true时,参数值表示值的列表,并且可以附加多个时间。 然后,值类型是列表

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
2
foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
3 < P> SE有关更详细的用例,请参见参数测试。

位置参数

位置参数是一个未命名的参数,只能通过其在命令行参数列表中的顺序来识别。 例如,前两个参数(标志和命名参数除外)可以检测为位置参数,并与相应的变量匹配。

单个位置参数

假设我们有cli语法:git push<;origin>;git当然是应用程序的二进制名称,push是一个子命令,它有两个位置参数:originmaster

要创建位置参数规则规范,请使用:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
4

名称-内部参数名称,用于引用参数值

帮助-帮助输出中显示的参数说明

必需-是否需要位置参数。 如果需要,但没有给出,则会引发语法错误。

默认值-参数的默认值,如果未给定(且不是必需的)

type-参数值的类型(例如str、int、float) 这里也可以提供对解析器函数的引用。 然后通过将字符串参数值传递给该函数来计算参数值。

选项-参数值可用选项的显式列表 或引用将被调用以检索此类可能值列表的函数。

严格的选项-是否应根据可用选项验证给定参数

示例:pos args.py

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
5

用法:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
6

请参阅作为规范的位置参数测试。

许多位置参数

cliglue允许匹配所有剩余(尚未匹配)参数。 当使用docker cmd这样的语法时,它很有用: docker运行命令ubuntu/bin/bash-c/script.sh 使用该语法,ubuntu-/bin/bash-c/script.sh之后的所有参数都应该与一个变量匹配。

您可以使用cliglue使用arguments。 该规则将强制解析器将所有剩余的参数存储在一个列表变量中(或一个连接的字符串中)。

要创建"多参数"规则规范,请使用:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
7

它允许检索特定数量的cli argumetns或所有剩余的参数。 所有匹配的参数将被提取到参数列表或字符串中(取决于用参数连接的

名称-内部变量名称,用于引用匹配的参数

类型-参数值的显式类型(例如str、int、float) 这里也可以提供对解析器函数的引用。 然后通过将字符串参数值传递给该函数来计算参数值

选项-参数值可用选项的显式列表 或引用将被调用以检索此类可能值列表的函数。

严格的选项-是否应根据可用选项验证给定参数

count-要检索的参数的显式数目。 如果未定义,则不验证参数计数。 如果您需要特定数量的参数,可以使用此计数,而不是设置min_count=max_count。

最小计数-最小参数数。 默认情况下,没有下限(为0)。

最大计数-最大参数数。 如果未定义,则参数计数没有上限。

连接了u-参数的可选字符串连接符。 如果设置好了,妈妈匹配的参数将用该连接符连接到字符串。 如果没有给出,匹配的参数将作为字符串列表传递。 当这个值(字符串或列表)被注入一个函数时,它可以通过指定的名称来访问。

帮助-帮助输出中显示的参数说明

注意,参数(count=1)规则与单个参数规则类似,只是它用一个元素存储列表。

只要设置了计数或最大计数,就可以使用许多连续的参数规则。

示例:many args.py

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
8

用法:

foo@bar:~$ ./hello.py --help
hello-appUsage:  ./hello.py [OPTIONS] NAMEOptions:  -h, --help [SUCOMMANDS...]       - Display this help and exit  --reverse                         --repeat REPEAT                 
9

有关更详细的用例,请参见许多参数测试

词典

字典包含键值对。 通过以以下方式传递参数,可以向其添加多个值: -c name1 value1-c name2 value2

默认情况下,它存储空的python dict。 这些值以后可以通过其显式名称或关键字引用为dict (小写格式,不带连字符前缀,带下划线而不是破折号, 例如,--配置名将被注入为配置名变量名)

要创建字典规则规范,请使用:

foo@bar:~$ ./hello.py world
Hello world.
0

关键字-与此词典匹配的关键字参数。 关键字可以使用直接格式传递:-c--config, 以及按名称:cconfig,将计算为-c--config。 单字符词典将得到单连字符前缀(-c), 较长的字典名称将得到双连字符前缀(--config

名称-显式内部字典名称(可用于与任何关键字区分)

帮助-帮助输出中显示的词典说明

键类型-字典键的类型(例如str、int、float) 这里也可以提供对解析器函数的引用。 然后通过将字符串参数值传递给该函数来计算字典值。

value_type-字典值的类型(例如str、int、float) 这里也可以提供对解析器函数的引用。 然后通过将字符串参数值传递给该函数来计算字典值。

基本字典示例:

foo@bar:~$ ./hello.py world
Hello world.
1
foo@bar:~$ ./hello.py world
Hello world.
2

有关更详细的用例,请参见字典测试

自动完成

shell自动完成允许在键入命令行时提示有关如何按tab键的最相关提示。

默认情况下,根据声明的子命令和选项,所有已知关键字都将启用由cliglue提供的自动完成功能。

定义可能的选择可能会导入自动完成参数。您可以声明显式可能值列表或在运行时提供此列表的函数。

完成符.py

foo@bar:~$ ./hello.py world
Hello world.
3

为了启用自动完成,您需要安装一些bash扩展。幸运的是,cliglue有内置的工具可以做到这一点:

foo@bar:~$ ./hello.py world
Hello world.
4

现在,我们已经在/usr/bin/中安装了completers demo应用程序(指向当前脚本的符号链接)和bash completion脚本。 键入时,我们可以按[tab]键完成命令。下面是一些完成示例:

foo@bar:~$ ./hello.py world
Hello world.
5

自定义完成符

您可以为选项参数提供自定义的自动完成符(可能值的提供者)。

例如,返回可用屏幕列表的函数:

foo@bar:~$ ./hello.py world
Hello world.
6

您可以使用它来验证和建议参数或位置参数:

foo@bar:~$ ./hello.py world
Hello world.
7

安装自动完成功能

为了启用自动完成,必须在/etc/bash_completion.d/中有一个特定的脚本。 使用cliglue您只需运行:

foo@bar:~$ ./hello.py world
Hello world.
8

它将安装自动完成脚本并在/usr/bin/中添加符号链接, 因此,您可以使用sample app命令而不是/sample-app.py

现在您可以键入示例应用程序并点击选项卡查看可能的命令和选项。

如果您键入sample app--he,它将自动填充唯一可能的选项:--help

有时候,你需要对代码进行一些修改, 但在这些修改之后,您将不需要重新安装自动完成功能。 您只需执行一次,因为自动完成脚本只重定向其查询并运行sample廑app.py

foo@bar:~$ ./hello.py world
Hello world.
9

自动完成是如何工作的?

  1. bash中键入命令时,请按选项卡键。(your-app.py命令[选项卡]
  2. bash/etc/bash_completion.d/中查找自动完成脚本。 在应用程序上运行--bash install之后,应该为命令安装一个脚本。 所以当找到这个脚本时,bash会调用它。
  3. 自动完成脚本重定向到应用程序,使用--bash autocomplete选项运行它,即脚本运行your-app.py--bash autocomplete"cmd",要求它返回最相关的命令建议。 注意,以这种方式,自动完成算法始终以最新版本运行。
  4. 默认情况下,app.py已启用--bash autocomplete选项,因此它将开始分析cli定义中与当前键入的单词最相关的关键字(cmd)。
  5. 如果您定义了自定义补全函数,将立即调用它们(如果需要),以便获取最新的建议并对其进行分析。
  6. 您的app.py向bash返回建议列表
  7. bash显示这些结果。 如果只有一个匹配的建议,则自动填充当前键入的单词。

请注意,每次尝试获取匹配参数建议时,您的应用程序都在运行。

自动生成的帮助

cliglue根据定义的cli规则自动生成帮助和使用情况输出。

假设我们有相当复杂的cli定义:

say_hello(name='world',reverse=False,repeat=1)
0

我们可以使用--help-h

查看命令的用法和说明
say_hello(name='world',reverse=False,repeat=1)
1

子命令帮助

我们还可以仅检查选定子命令的用法:

say_hello(name='world',reverse=False,repeat=1)
2

版本检查

使用--version显示应用程序版本:

say_hello(name='world',reverse=False,repeat=1)
3

数据类型

cliglue支持参数或位置参数的类型化值。 默认情况下,所有值都有字符串类型。 可以通过定义类型参数来更改。

有两种可能的类型值:

  • 键入名称本身(例如intstrfloat
  • 返回值的分析器的引用 在这两种情况下,通过调用类型(str_value)计算内部变量值。 当参数值的格式无效时,会产生语法错误。

基本类型(int、float等)

say_hello(name='world',reverse=False,repeat=1)
4
say_hello(name='world',reverse=False,repeat=1)
5

内置数据类型

cliglue为某些类型提供了内置的解析器/验证器

文件系统类型
  • cliglue.types.filesystem.existing_file验证给定字符串是否是现有的常规文件(而不是目录)。 验证后,该值在内部存储为str
α-αα66
  • cliglue.types.filesystem.existing_directory验证给定字符串是否为现有目录。 验证后,该值在内部存储为str
say_hello(name='world',reverse=False,repeat=1)
7

日期时间类型
  • cliglue.types.time.iso_date以iso格式将给定字符串解析/验证为日期:%y-%m-%d。 验证后,该值在内部存储为datetime.datetime
say_hello(name='world',reverse=False,repeat=1)
8
  • cliglue.types.time.iso_time以iso格式将给定字符串解析/验证为时间:%h:%m:%s。 验证后,该值在内部存储为datetime.datetime
say_hello(name='world',reverse=False,repeat=1)
9
  • cliglue.types.time.iso_time以ISO格式将给定字符串解析/验证为日期时间:%y-%m-%d%h:%m:%s。 验证后,该值在内部存储为datetime.datetime
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
0

示例:

foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
1
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
2
  • cliglue.types.time.datetime_format以用户指定的自定义格式将给定字符串解析/验证为datetime。 您可以指定多个格式,并且将按顺序分析每个格式的cli参数。 返回第一个成功分析的日期时间。 之后,该值在内部存储为datetime.datetime
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
3
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
4
  • cliglue.types.time.today_format以用户指定的自定义格式将给定字符串解析/验证为时间。 它从输入中获取时间,并将其与今天的日期相结合。 您可以指定多个格式,并且将按顺序分析每个格式的cli参数。 返回第一个成功分析的日期时间。 之后,该值在内部存储为datetime.datetime
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
5
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
6

自定义类型分析器

您可以定义自定义解析器/验证器函数。 它应该接受一个str参数并返回预期的值类型。

foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
7
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
8

错误处理

cliglue在运行时验证传递的cli参数clibuilder.run()

处理语法错误-clisyntaxerror

如果出现语法错误,clibuilder.run()会引发clisyntaxerror,此时:

  • 缺少参数值:--参数名不带下一个参数
  • 未提供必需的参数
  • 未给出所需的位置参数
  • 位置参数或参数的类型无效(存在解析类型错误)

默认情况下,由clibuilder捕获的clisyntaxerror 您可以通过在创建clibuilder时设置reraise_error=false来禁用再次引发此错误: clibuilder(reraise_error=false)。 然后,控制台标准输出中将只显示错误日志。

用法错误参数决定语法错误时应显示用法输出。

错误处理示例
foo@bar:~$ ./hello.py --reverse world --repeat 2Hello dlrow.Hello dlrow.
9
foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
0

clidefinitionerror

如果cli定义无效,clibuilder.run()将引发clidefinitionerror。例如,时间:

  • 位置参数或参数设置为"必需",并设置了默认值(没有任何意义)
  • 位置参数放在所有剩余参数之后
  • 参数/参数值不属于严格可用选项列表

错误的cli定义示例
foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
1
foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
2

cli规则备忘表

以下是最重要的cli规则的备忘表:

foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
3

复杂的cli树

下面是一个更复杂的cli定义树示例:

多应用程序.py

foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
4

用法:

foo@bar:~$ ./hello.py world --repeat=2 --reverse
Hello dlrow.Hello dlrow.
5

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java播放流媒体音乐   LWJGL中的java纹理未显示   java从父集合中删除时删除子对象   mysql希望在我的代码中添加验证,如果表不存在,它应该用java创建新表   java我可以关闭客户端的socket而不引起服务器端的EOFEException吗?   java Primefaces对话框框架咆哮和showMessageInDialog不工作   hadoop配置单元无法初始化类java。网网络接口   关键字中缺少oracle11g Java iBatis   java在RESTAPI中创建PUT和POST端点,而不创建GET端点?   java Math abs和ceil输出编译错误   java Tomcat 8.017代md5及其摘要。球棒   java SpringBean配置xml文件在IteliJ Idea中加载   java为什么在使用Powershell指定Xms和Xmx时,它们什么都不做,但通过Netbeans IDE可以正常工作?   java Drools项目构建失败,kjar打包从7.7版开始