Click包(2)
文章目录
提示用户输入¶
单击支持在两个不同位置的提示。第一个是发生参数处理时的自动提示,第二个是在以后的某个时间单独询问提示。
这可以通过prompt()
根据类型要求有效输入的confirm()
功能或要求确认(是/否)的功能来完成。
选项提示
选项提示已集成到选项界面中。有关更多信息,请参见 提示。在内部,它会自动调用prompt()
或confirm()
根据需要调用。
输入提示
要手动要求用户输入,可以使用该prompt()
功能。默认情况下,它接受任何Unicode字符串,但是您可以要求任何其他类型。例如,您可以要求一个有效的整数:
value = click.prompt('Please enter a valid integer', type=int)
此外,如果提供默认值,则将自动确定类型。例如,以下内容仅接受浮点数:
value = click.prompt('Please enter a number', default=42.0)
确认提示
要询问用户是否要继续执行某项操作,该confirm()
功能非常方便。默认情况下,它以布尔值返回提示的结果:
if click.confirm('Do you want to continue?'):
click.echo('Well done!')
如果没有返回,还可以选择使函数自动中止程序的执行True
:
click.confirm('Do you want to continue?', abort=True)
文档脚本
单击可以非常轻松地记录命令行工具。首先,它会自动为您生成帮助页面。尽管目前无法根据布局自定义这些内容,但可以更改所有文本。
帮助文本
命令和选项接受帮助参数。在使用命令的情况下,将自动使用该函数的文档字符串(如果提供)。
简单的例子:
@click.command()
@click.option('--count', default=1, help='number of greetings')
@click.argument('name')
def hello(count, name):
"""This script prints hello NAME COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
看起来像什么:
$ hello --help
Usage: hello [OPTIONS] NAME
This script prints hello NAME COUNT times.
Options:
--count INTEGER number of greetings
--help Show this message and exit.
记录参数
click.argument()
不带help
参数。这是为了遵循Unix工具的一般约定,即仅对最必要的东西使用参数,并通过按名称引用它们来在命令帮助文本中记录它们。
您可能希望在描述中引用该参数:
@click.command()
@click.argument('filename')
def touch(filename):
"""Print FILENAME."""
click.echo(filename)
看起来像什么:
$ touch --help
Usage: touch [OPTIONS] FILENAME
Print FILENAME.
Options:
--help Show this message and exit.
或者,您可能希望显式提供参数的描述:
@click.command()
@click.argument('filename')
def touch(filename):
"""Print FILENAME.
FILENAME is the name of the file to check.
"""
click.echo(filename)
看起来像什么:
$ touch --help
Usage: touch [OPTIONS] FILENAME
Print FILENAME.
FILENAME is the name of the file to check.
Options:
--help Show this message and exit.
有关更多示例,请参见Arguments中的示例。
防止包装
Click的默认行为是根据终端的宽度重新包装文本。在某些情况下,这可能会成为问题。主要问题是在显示代码示例时,其中的换行符很重要。
通过添加仅包含\b
转义标记的行,可以逐段禁用重新包装。该行将从帮助文本中删除,并且重新包装将被禁用。
例:
@click.command()
def cli():
"""First paragraph.
This is a very long second paragraph and as you
can see wrapped very early in the source text
but will be rewrapped to the terminal width in
the final output.
\b
This is
a paragraph
without rewrapping.
And this is a paragraph
that will be rewrapped again.
"""
看起来像什么:
$ cli --help
Usage: cli [OPTIONS]
First paragraph.
This is a very long second paragraph and as you can see wrapped very early
in the source text but will be rewrapped to the terminal width in the final
output.
This is
a paragraph
without rewrapping.
And this is a paragraph that will be rewrapped again.
Options:
--help Show this message and exit.
截断帮助文本
单击可从函数文档字符串获取命令帮助文本。但是,如果您已经使用文档字符串来记录函数参数,则可能不希望在帮助文本中看到:param:和:return:行。
您可以使用\f
转义标记使Click截断标记后的帮助文本。
例:
@click.command()
@click.pass_context
def cli(ctx):
"""First paragraph.
This is a very long second
paragraph and not correctly
wrapped but it will be rewrapped.
\f
:param click.core.Context ctx: Click context.
"""
看起来像什么:
$ cli --help
Usage: cli [OPTIONS]
First paragraph.
This is a very long second paragraph and not correctly wrapped but it will
be rewrapped.
Options:
--help Show this message and exit.
元变量
选项和参数接受metavar
可以更改帮助页面中的meta变量的参数。默认版本是带下划线的大写参数名称,但可以根据需要用不同的方式注释。可以在所有级别上自定义:
@click.command(options_metavar='<options>')
@click.option('--count', default=1, help='number of greetings',
metavar='<int>')
@click.argument('name', metavar='<name>')
def hello(count, name):
"""This script prints hello <name> <int> times."""
for x in range(count):
click.echo('Hello %s!' % name)
例:
$ hello --help
Usage: hello <options> <name>
This script prints hello <name> <int> times.
Options:
--count <int> number of greetings
--help Show this message and exit.
命令快捷帮助
对于命令,将生成一个简短的帮助代码段。默认情况下,它是命令帮助消息的第一句话,除非它太长。这也可以被覆盖:
@click.group()
def cli():
"""A simple command line tool."""
@cli.command('init', short_help='init the repo')
def init():
"""Initializes the repository."""
@cli.command('delete', short_help='delete the repo')
def delete():
"""Deletes the repository."""
看起来像什么:
$ repo.py
Usage: repo.py [OPTIONS] COMMAND [ARGS]...
A simple command line tool.
Options:
--help Show this message and exit.
Commands:
delete delete the repo
init init the repo
帮助参数自定义
变更日志help参数以非常特殊的方式在Click中实现。与常规参数不同,Click是为任何命令自动添加的,它会自动解决冲突。默认情况下称为--help
,但是可以更改。如果命令本身实现了具有相同名称的参数,则默认的帮助参数将停止接受它。有一个上下文设置,可用于覆盖称为的帮助参数的名称help_option_names
。
本示例将默认参数更改为-h
和,--help
而不仅仅是--help
:
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.command(context_settings=CONTEXT_SETTINGS)
def cli():
pass
看起来像什么:
$ cli -h
Usage: cli [OPTIONS]
Options:
-h, --help Show this message and exit.
复杂的应用程序
Click旨在帮助创建复杂和简单的CLI工具。但是,其设计的能力是将系统任意嵌套在一起的能力。例如,如果您曾经使用过Django,您将意识到它提供了命令行实用程序,但是Celery也是如此。将Celery与Django结合使用时,有两个工具需要相互交互并进行交叉配置。
在两个单独的Click命令行实用程序的理论世界中,它们可以通过将一个嵌套在另一个内部来解决此问题。例如,Web框架还可以加载消息队列框架的命令。
基本概念
要了解其工作原理,您需要了解两个概念:上下文和调用约定。
上下文
每当执行Click命令时,Context
都会创建一个对象,该对象保留此特定调用的状态。它记住已解析的参数,创建该命令的命令,在函数末尾需要清除哪些资源等等。它还可以选择保存应用程序定义的对象。
上下文对象会建立一个链接列表,直到它们到达顶部为止。每个上下文都链接到父上下文。这使一个命令可以在另一个命令之下工作,并在其中存储自己的信息,而不必担心更改父命令的状态。
但是,由于可以使用父数据,因此可以根据需要导航到它。
大多数时候,您不会看到上下文对象,但是在编写更复杂的应用程序时会很方便。这将我们带到了下一点。
调用约定
当执行Click命令回调时,会将所有非隐藏参数作为关键字参数传递。上下文明显不存在。但是,可以通过使用标记自身来选择将回调传递给上下文对象pass_context()
。
那么,如果不知道是否应该接收上下文,该如何调用命令回调?答案是上下文本身提供了一个辅助功能(Context.invoke()
),可以为您完成此操作。它接受回调作为第一个参数,然后正确调用该函数。
构建一个Git克隆
在此示例中,我们要构建一个类似于版本控制系统的命令行工具。像Git这样的系统通常会提供一个已接受某些参数和配置的总体命令,然后再提供执行其他操作的额外子命令。
根命令
在顶层,我们需要一个可以容纳所有命令的组。在这种情况下,我们使用click.group()
允许在其下面注册其他Click命令的基本方法。
对于此命令,我们还希望接受一些配置工具状态的参数:
import os
import click
class Repo(object):
def __init__(self, home=None, debug=False):
self.home = os.path.abspath(home or '.')
self.debug = debug
@click.group()
@click.option('--repo-home', envvar='REPO_HOME', default='.repo')
@click.option('--debug/--no-debug', default=False,
envvar='REPO_DEBUG')
@click.pass_context
def cli(ctx, repo_home, debug):
ctx.obj = Repo(repo_home, debug)
让我们了解它的作用。我们创建一个可以包含子命令的组命令。调用它时,它将创建一个Repo
类的实例 。这保留了命令行工具的状态。在这种情况下,它只记住一些参数,但是此时它也可以开始加载配置文件,依此类推。
然后,上下文会将该状态对象记住为obj
。这是一个特殊的属性,在该属性中,命令应该记住要传递给子级的内容。
为了使它起作用,我们需要用标记我们的函数 pass_context()
,因为否则,上下文对象将对我们完全隐藏。
第一个子命令
让我们向其添加第一个子命令克隆命令:
@cli.command()
@click.argument('src')
@click.argument('dest', required=False)
def clone(src, dest):
pass
所以现在我们有了一个克隆命令,但是如何获得对存储库的访问权限呢?您可以想象,一种方法是使用该pass_context()
函数,该函数将再次使我们的回调也获得我们存储该存储库的上下文。但是,此装饰器的第二个版本称为pass_obj()
,它将仅传递存储的对象(在本例中为repo):
@cli.command()
@click.argument('src')
@click.argument(&