使用invoke作为库¶
虽然我们的大多数文档都涉及面向任务管理和命令执行的用户/ CLI用例,但是调用是为其组成部分设计的,可以由高级用户独立使用,或者是箱外的或最少的额外工作。cli解析、子流程命令执行、任务组织等都是作为广泛分离的关注点编写的。
本文档概述了已知可用的用例(因为下游工具,如 Fabric 已经在利用它们)。
将invoke的cli模块重用为不同的二进制文件¶
一个主要的用例是在幕后使用invoke分发您自己的程序,绑定到不同的二进制名称,并且通常设置一个特定的任务 namespace 作为默认值。(这与 argparse
在某些情况下,还需要删除、替换和/或添加核心cli标志。
正在设置¶
假设要分发名为 tester
提供两个子命令, unit
和 integration
,这样用户就可以 pip install tester
并且可以访问如下命令 tester unit
, tester integration
或 tester integration --fail-fast
.
首先,与任何提供cli“二进制文件”的不同python包一样,您将通知 setup.py
你的入口点:
setup(
name='tester',
version='0.1.0',
packages=['tester'],
install_requires=['invoke'],
entry_points={
'console_scripts': ['tester = tester.main:program.run']
}
)
备注
这只是一个示例代码片段,并不是完全有效的 setup.py
;如果您不知道Python打包是如何工作的,一个很好的起点是 the Python Packaging User's Guide 。
这里没有特定的调用-这是告诉python安装 tester
执行 run
A方法 program
在模块内定义的对象 tester.main
.
创建一个 Program
¶
在我们 tester/main.py
,我们开始导入invoke的公共cli功能:
from invoke import Program
然后我们定义 program
我们引用的对象 setup.py
,这很简单 Program
为了完成这项繁重的工作,请先给出我们的版本号:
program = Program(version='0.1.0')
此时,正在安装 tester
将提供与invoke相同的功能 built-in CLI tool ,命名除外 tester
并公开自己的版本号:
$ tester --version
Tester 0.1.0
$ tester --help
Usage: tester [--core-opts] task1 [--task1-opts] ... taskN [--taskN-opts]
Core options:
... core Invoke options here ...
$ tester --list
Can't find any collection named 'tasks'!
这对我们还没有多大好处-没有任何子命令(我们的用户也不关心任意的“任务”,所以invoke自己的默认值 --help
和 --list
输出不太合适)。
指定子命令¶
为了 tester
揭露 unit
和 integration
子命令,我们需要在常规的invoke tasks模块中定义它们,或者 namespace . 在我们的例子中,我们将创建 tester/tasks.py
(但你会看到,这也是任意的,可以是你喜欢的任何东西):
from invoke import task
@task
def unit(c):
print("Running unit tests!")
@task
def integration(c):
print("Running integration tests!")
如上所述 构造命名空间 您可以根据需要安排这个模块——为了简洁起见,上面的代码段使用隐式命名空间。
备注
重要的是要认识到这些“子命令”没有什么特别之处——您可以使用vanilla invoke(例如via)轻松地运行它们。 invoke --collection=tester.tasks --list
.
现在有用的是:告诉我们的习俗 Program
此任务命名空间应用作 tester
,通过 namespace
克瓦格:
from invoke import Collection, Program
from tester import tasks
program = Program(namespace=Collection.from_module(tasks), version='0.1.0')
结果呢?
$ tester --version
Tester 0.1.0
$ tester --help
Usage: tester [--core-opts] <subcommand> [--subcommand-opts] ...
Core options:
... core options here, minus task-related ones ...
Subcommands:
unit
integration
$ tester --list
No idea what '--list' is!
$ tester unit
Running unit tests!
注意“usage”行是如何更改的(以指定“subcommands”而不是“tasks”);特定子命令的列表现在作为 --help
;和 --list
已从选项中删除。
您可以启用 tab-completion 对于不同的二进制和子命令。
修改核心分析器参数¶
这个用例的一个常见需求是调整核心解析器参数。 Program
轻松:默认核心 Arguments
由返回 Program.core_args
. 将此方法的返回值扩展为 super
你就完了:
# Presumably, this is your setup.py-designated CLI module...
from invoke import Program, Argument
class MyProgram(Program):
def core_args(self):
core_args = super().core_args()
extra_args = [
Argument(names=('foo', 'f'), help="Foo the bars"),
# ...
]
return core_args + extra_args
program = MyProgram()
警告
我们不推荐 省略 任何现有的核心参数;许多基本功能都依赖于它们的存在,即使保留默认值也是如此。
自定义配置系统的默认值¶
除了上一节中面向cli的内容之外,在重新分发invoke codebase(cli或no cli)时经常需要更新的另一个功能领域是配置。这里通常有两个问题:
配置文件名和env var前缀-如果您希望用户使用配置系统,那么这一点至关重要;
默认配置值-不太重要(大多数默认值没有标记任何调用特定的内容),但有时仍然是可取的。
更改文件名和/或env var前缀¶
默认情况下,invoke的配置系统会查找如下文件 /etc/invoke.yaml
, ~/.invoke.json
,等等,如果您正在分发名为其他名称的客户端代码,如 Tester
例如,您可能希望加载配置系统 /etc/tester.json
或 $CWD/tester.py
.
类似地,环境变量config level查找如下环境变量 INVOKE_RUN_ECHO
;你可能更喜欢 TESTER_RUN_ECHO
.
有几个 Config
控制这些值的属性:
prefix
:一个通用的catchall前缀,直接用作文件前缀,并通过所有大写字母用作env var前缀;file_prefix
:仅重写文件名前缀-否则,默认值为prefix
;env_prefix
:对于只重写env var前缀-正如您可能已经猜到的,它也默认为prefix
.
继续我们的“测试员”示例,您将执行以下操作:
from invoke import Config
class TesterConfig(Config):
prefix = 'tester'
或者,寻求 tester.yaml
和以前一样,但是 TEST_RUN_ECHO
而不是 TESTER_RUN_ECHO
::
class TesterConfig(Config):
prefix = 'tester'
env_prefix = 'TEST'
修改默认配置值¶
默认配置值很简单-它们只是staticmethod的返回值 Config.global_defaults
,所以重写它并返回您喜欢的任何内容-理想情况下是基于超类的值,因为系统的其他部分假设存在许多默认值。(helper函数 invoke.config.merge_dicts
在这里很有用。
例如,假设您希望tester在您的代码基调用时总是在默认情况下回显shell命令 Context.run
::
from invoke import Program
from invoke.config import Config, merge_dicts
class TesterConfig(Config):
@staticmethod
def global_defaults():
their_defaults = Config.global_defaults()
my_defaults = {
'run': {
'echo': True,
},
}
return merge_dicts(their_defaults, my_defaults)
program = Program(config_class=TesterConfig, version='0.1.0')
作为参考,invoke自己的基本默认值(您可以说,…默认值)记录在 默认配置值 .