教程¶
本教程将指导你完成安装、配置和运行 Nox。
安装¶
Nox 可以通过 pip 轻松安装。
python3 -m pip install nox
你可能想使用 user site,以避免搞乱你的全局 Python 安装:
python3 -m pip install --user nox
或者你可以更花哨一些,使用 pipx:
pipx install nox
无论如何,Nox 通常是 全局 范围内安装的,类似于 tox
、pip
和其他类似工具。
如果你对在 docker 中运行 nox
感兴趣,你可以使用 DockerHub 上的 thekevjames/nox images,其中包含所有 nox
版本和所有支持的 python
版本的构建。
如果你想在 GitHub Actions 中运行 nox
,你可以使用 excitedleigh/setup-nox action,它安装了最新的 nox
,并使 GitHub Actions 环境提供的所有 Python 版本可用。
编写配置文件¶
Nox 是通过你的项目目录中一个叫做 noxfile.py
的文件配置的。这个文件是一个 Python 文件,定义了一组 sessions。一个 session 是一个环境和一组在该环境中运行的命令。如果你对 tox 熟悉的话,session 类似于 environments。如果你熟悉 GNU Make,session 就类似于 targets。
会话是使用 @nox.session
装饰器来声明的。这类似于 Flask 使用 @app.route
的方式。
这是一个基本的 Noxfile,针对 example.py
运行 flake8 (你可以自己创建 example.py
)
import nox
@nox.session
def lint(session):
session.install("flake8")
session.run("flake8", "example.py")
第一次运行 Nox¶
现在你已经安装了 Nox 并有一个 Noxfile ,你可以运行 Nox 了!在终端打开你的项目目录,运行 nox
。你应该看到像这样的东西:
$ nox
nox > Running session lint
nox > Creating virtualenv using python3.7 in .nox/lint
nox > pip install flake8
nox > flake8 example.py
nox > Session lint was successful.
✨ 你现在已经成功地第一次使用了 Nox! ✨
本教程的其余部分将带你了解你可能想用 Nox 做的其他普通事情。如果你愿意,你也可以跳到 命令行用法 和 配置和 API 文档中。
安装依赖¶
Nox 或多或少将 session.install
传递给 pip
,所以你可以用通常的方式安装东西。这里有一些例子:
要一次安装一个或多个软件包:
@nox.session
def tests(session):
# same as pip install pytest protobuf>3.0.0
session.install("pytest", "protobuf>3.0.0")
...
要安装 requirements.txt
文件:
@nox.session
def tests(session):
# same as pip install -r requirements.txt
session.install("-r", "requirements.txt")
...
如果你的项目是 Python 包,你想安装它:
@nox.session
def tests(session):
# same as pip install .
session.install(".")
...
在某些情况下,例如 Python 二进制扩展,你的软件包可能依赖于在 Python 生态系统之外编译的代码。要确保在安装过程中,低级别的依赖关系(例如 libfoo
)是可用的
@nox.session
def tests(session):
...
session.run_always(
"cmake", "-DCMAKE_BUILD_TYPE=Debug",
"-S", libfoo_src_dir,
"-B", build_dir,
external=True,
)
session.run_always(
"cmake",
"--build", build_dir,
"--config", "Debug",
"--target", "install",
external=True,
)
session.install(".")
...
运行命令¶
session.run
函数让你在会话的虚拟环境中运行命令。这里有几个例子:
你可以安装和运行 Python 工具:
@nox.session
def tests(session):
session.install("pytest")
session.run("pytest")
如果你想给程序传递更多的参数,只需在 run
中添加更多的参数:
@nox.session
def tests(session):
session.install("pytest")
session.run("pytest", "-v", "tests")
你也可以传递环境变量:
@nox.session
def tests(session):
session.install("black")
session.run(
"pytest",
env={
"FLASK_DEBUG": "1"
}
)
参见 nox.session.Session.run()
,了解更多运行程序的选项和例子。
选择要运行的会话¶
一旦你的 Nox 文件中有多个会话,你会发现 Nox 会默认运行它们。虽然这很有用,但通常一次只运行一个或两个是有用的。你可以使用 --sessions
参数(或 -s
)来选择运行哪些会话。你可以使用 --list
参数来显示哪些会话是可用的,哪些将被运行。这里有一些例子:
这里有一个有三个会话的 Noxfile:
import nox
@nox.session
def test(session):
...
@nox.session
def lint(session):
...
@nox.session
def docs(session):
...
如果你只是运行 nox --list
,你会看到所有会话都被选中:
Sessions defined in noxfile.py:
* test
* lint
* docs
sessions marked with * are selected,
sessions marked with - are skipped.
如果你运行 nox --list --sessions lint
,你会看到只有 lint 会话被选中:
Sessions defined in noxfile.py:
- test
* lint
- docs
sessions marked with * are selected,
sessions marked with - are skipped.
而如果你运行 nox --sessions lint
,Nox 将只运行 lint 会话:
nox > Running session lint
nox > Creating virtualenv using python3 in .nox/lint
nox > ...
nox > Session lint was successful.
在 noxfile 中,你可以指定一组默认的会话来运行。如果是这样,普通的 nox
调用将只触发某些会话:
import nox
nox.options.sessions = ["lint", "test"]
如果你将此设置为空列表,Nox 默认不会运行任何会话,当用户没有指定要运行的会话时,会用 --list
输出打印一条有用的信息。
选择和运行会话的方法还有很多! 你可以在 命令行用法 中阅读更多关于调用 Nox 的信息。
会话队列¶
如果你想从当前会话中排队(或 “notify”)另一个会话,你可以使用 session.notify
函数:
@nox.session
def tests(session):
session.install("pytest")
session.run("pytest")
# Here we queue up the test coverage session to run next
session.notify("coverage")
@nox.session
def coverage(session):
session.install("coverage")
session.run("coverage")
你可以排队任何你想要的会话,不仅仅是测试和覆盖会话,但这是一个非常常用的模式。
现在运行 nox --session tests
将运行测试会话,然后是覆盖会话。
你也可以传递被通知的会话位置参数:
@nox.session
def prepare_thing(session):
thing_path = "./path/to/thing"
session.run("prepare", "thing", thing_path)
session.notify("consume_thing", posargs=[thing_path])
@nox.session
def consume_thing(session):
# The 'consume' command has the arguments
# sent to it from the 'prepare_thing' session
session.run("consume", "thing", session.posargs)
注意,这只有在通过 --session/-s
标志选择要运行的会话时才会产生预期效果。如果你简单地运行 nox
,所有选择的会话都会被运行。
对不同的和多个 Python 进行测试¶
许多项目需要支持特定版本的 Python 或多个 Python 版本。你可以通过指定 python
到 @nox.session
,让 Nox 针对多个解释器运行你的会话。这里有一些例子:
如果你希望你的会话只针对单一版本的 Python 运行:
@nox.session(python="3.7")
def test(session):
...
如果你想让你的会话针对多个版本的 Python 运行:
@nox.session(python=["2.7", "3.6", "3.7"])
def test(session):
...
你会注意到,运行 nox --list
将显示这一个会话已经扩展为三个不同的会话:
Sessions defined in noxfile.py:
* test-2.7
* test-3.6
* test-3.7
你可以使用 nox --sessions test
来运行所有的 test
会话,或者使用列表中显示的全名来运行单个会话,例如,nox --sessions test-3.5
。关于选择会话的更多细节可以在 命令行用法 文档中找到。
你可以在 配置会话的 virtualenv 上阅读更多关于配置你的会话所使用的虚拟环境的信息。
用 conda 测试¶
有些项目,尤其是数据科学界的项目,需要测试它们在 conda 环境下的工作。如果你想让你的会话在 conda 环境下运行:
@nox.session(venv_backend="conda")
def test(session):
...
用 conda 安装软件包:
session.conda_install("pytest")
用 pip 安装软件包到 conda 环境是可能的,但最好的做法是只用 --no-deps
选项来安装 pip 软件包。这样可以防止 pip 通过安装与 conda 已经安装的软件包不兼容的版本来破坏 conda 环境。
session.install("contexter", "--no-deps")
session.install("-e", ".", "--no-deps")
"mamba"
也允许作为 venv_backend
的选择,它将使用/要求 mamba 而不是 conda。
参数化¶
就像 Nox 可以处理针对多个解释器的运行,Nox 也可以处理用不同的参数列表来运行你的会话,并使用 nox.parametrize()
装饰器。
这里有一个使用参数化来测试两个不同版本的 Django 的简短例子:
@nox.session
@nox.parametrize("django", ["1.9", "2.0"])
def test(session, django):
session.install(f"django=={django}")
session.run("pytest")
如果你运行 nox --list
,你会看到 Nox 将你的一个会话扩展为多个会话。每个参数值都有一个,你想把它传给你的会话:
Sessions defined in noxfile.py:
* test(django='1.9')
* test(django='2.0')
nox.parametrize()
的接口和用法有意类似于 pytest 的 parametrize。它是 Nox 的一个非常强大的功能。你可以在 参数化会话 上阅读更多关于参数化的信息并看到更多的例子。
下一步¶
看看你! 你现在基本上已经是 Nox 的专家了! ✨
对于这一点,你可以:
玩得开心! 💜