Python命令行创建工具包——Click(2)

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(&
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值