教程

本教程将指导你完成安装、配置和运行 Nox。

安装

Nox 可以通过 pip 轻松安装。

python3 -m pip install nox

你可能想使用 user site,以避免搞乱你的全局 Python 安装:

python3 -m pip install --user nox

或者你可以更花哨一些,使用 pipx

pipx install nox

无论如何,Nox 通常是 全局 范围内安装的,类似于 toxpip 和其他类似工具。

如果你对在 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 的专家了! ✨

对于这一点,你可以:

玩得开心! 💜