为 Numba 做贡献
我们欢迎所有希望为 Numba 做出贡献的人,无论贡献大小!即使是简单的文档改进也受到鼓励。如果您有问题,请随时提问(见下文)。
交流
实时聊天
Numba 使用 Gitter 进行公共实时聊天。为了帮助提高信噪比,我们有两个频道:
numba/numba: 一般的 Numba 讨论、问题和调试帮助。
numba/numba-dev: PR 讨论、规划、发布协调等。
两个频道都是公开的,但我们可能会要求 numba-dev 上的讨论转移到 numba 频道。这只是为了确保核心开发者能够轻松跟进 numba-dev。
请注意,Github issue 跟踪器是报告 bug 的最佳地点。聊天中的 bug 报告难以追踪,很可能会丢失。
论坛
Numba 使用 Discourse 作为论坛,进行更长时间的讨论,例如设计讨论和路线图规划。有各种类别可用,可以通过以下地址访问:numba.discourse.group。
每周会议
Numba 核心开发者每周举行一次视频会议,讨论路线图、功能规划和未解决的问题。这些会议完全公开,详细信息发布在 numba.discourse.group 公告中,欢迎所有人加入讨论。会议纪要将被记录并发布到 Numba wiki。
Bug 追踪器
我们使用 Github issue 追踪器来追踪 bug 报告和功能请求。如果您报告问题,请包含具体细节:
您尝试做什么;
您的操作系统以及您正在运行的 Numba 版本;
Numba 如何出现异常行为,例如完整的错误回溯,或者您得到的不符合预期的结果;
尽可能提供允许完整重现您问题的代码片段。
开始设置
如果您想贡献,我们建议您分叉我们的 Github 仓库,然后创建一个分支来代表您的工作。当您的工作准备好后,您应该通过 Github 界面提交一个拉取请求(pull request)。
如果您愿意,即使您尚未完成工作,也可以提交拉取请求。这对于收集反馈,或针对 持续集成 平台测试您的更改可能很有用。在这种情况下,请在您的拉取请求标题前加上 [WIP]
。
构建环境
Numba 有许多依赖项(主要是 NumPy 和 llvmlite),它们的构建说明不简单。除非您想自己构建这些依赖项,否则我们建议您使用 conda 来创建专门的开发环境,并在其中安装这些依赖项的预编译版本。在此处阅读有关 Numba 依赖项的更多信息:numba-source-install-check。
在使用 Numba 源代码检出时,您还需要一个 llvmlite 的开发版本。这些可从 anaconda.org 上的 numba/label/dev
频道获取。
要创建具有所需依赖项的环境,请注意使用双冒号语法 (numba/label/dev::llvmlite
) 来安装 llvmlite 库的最新开发版本:
$ conda create -n numbaenv python=3.10 numba/label/dev::llvmlite numpy scipy jinja2 cffi
注意
这会安装基于 Python 3.10 的环境,但您当然可以选择 Numba 支持的另一个版本。要测试其他功能,您可能还需要安装 tbb
和/或 llvm-openmp
。有关详细信息,请查看上面的依赖项列表。
要激活当前 shell 会话的环境:
$ conda activate numbaenv
注意
这些说明适用于标准 Linux shell。您可能需要根据其他平台进行调整。
环境激活后,您将拥有一个具有所需依赖项的专用 Python:
$ python
Python 3.10.3 (main, Mar 28 2022, 04:26:28) [Clang 12.0.0 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import llvmlite
>>> llvmlite.__version__
0.39.0dev0+61.gf27ac6f
构建 Numba
为了方便开发工作流程,我们建议您在 Numba 源代码检出目录中构建 Numba:
$ git clone git@github.com:numba/numba.git
$ cd numba
$ python setup.py build_ext --inplace
这假定您的开发系统上有一个可用的 C 编译器和运行时。每当您修改 Numba 源代码树中的 C 文件时,您都必须再次运行此命令。
Numba 的设置中的 build_ext
命令还接受以下参数:
--noopt
: 这会在编译 Numba 的 CPython 扩展时禁用优化,这使得调试它们更加容易。建议与标准build_ext
选项--debug
结合使用。--werror
: 使用-Werror
标志编译 Numba 的 CPython 扩展。--wall
: 使用-Wall
标志编译 Numba 的 CPython 扩展。
请注意,Numba 的 CI 和 Linux 的 conda 配方都使用 --werror
和 --wall
标志进行构建,因此任何更改 CPython 扩展的贡献也应该使用这些标志进行测试。
运行测试
Numba 使用由各种测试(单元测试、功能测试)组成的测试套件进行验证。测试套件使用标准的 unittest
框架编写。
可以通过 python -m numba.runtests
执行测试。如果您是从源代码检出运行 Numba,可以输入 ./runtests.py
作为快捷方式。支持各种选项来影响测试运行和报告。传递 -h
或 --help
以了解这些选项。示例:
列出所有可用测试:
$ python -m numba.runtests -l
列出特定(子)套件中的测试:
$ python -m numba.runtests -l numba.tests.test_usecases
运行这些测试:
$ python -m numba.runtests numba.tests.test_usecases
使用多个子进程并行运行所有测试:
$ python -m numba.runtests -m
有关所有选项的详细列表:
$ python -m numba.runtests -h
Numba 测试套件可能需要很长时间才能完成。当您想避免长时间等待时,首先使用以下测试运行器选项关注失败的测试会很有用:
添加
--failed-first
选项以捕获失败测试列表并首先重新执行它们:$ python -m numba.runtests --failed-first -m -v -b
--last-failed
选项与--failed-first
一起使用,仅执行上次失败的测试:$ python -m numba.runtests --last-failed -m -v -b
调试时,打开日志记录很有用。Numba 使用标准 logging
模块记录日志。可以使用标准方法(即 logging.basicConfig
)配置日志记录行为。为了方便起见,测试运行器中有一个 --log
标志可以启用日志记录:
$ python -m numba.runtests --log
要启用 运行时类型检查,请设置环境变量 NUMBA_USE_TYPEGUARD=1
,并使用源代码根目录中的 runtests.py。例如:
$ NUMBA_USE_TYPEGUARD=1 python runtests.py
运行覆盖率
可以使用 coverage.py 生成覆盖率报告。要为测试套件记录覆盖率信息,请运行:
coverage run -m numba.runtests <runtests args>
接下来,使用以下命令合并覆盖率文件(可能包含多次运行的数据):
coverage combine
合并后的输出可以转换为各种报告格式——请参阅 coverage CLI 使用参考。例如,要生成 HTML 报告,请运行:
coverage html
执行此命令后,可以通过打开 htmlcov/index.html
查看报告。
开发规则
代码审查
任何非平凡的更改都应经过一个或多个核心开发人员的代码审查。推荐的流程是在 github 上提交拉取请求。
代码审查应尝试评估以下标准:
总体设计和正确性
代码结构和可维护性
编码约定
文档字符串、注释和发布说明(如果需要)
测试覆盖率
关于代码格式大规模更改的政策
请注意,对代码库进行大规模格式更改的拉取请求通常不被接受。此类更改通常会增加其他拉取请求发生合并冲突的可能性,这不可避免地需要时间和资源来解决。它们还需要大量的精力来检查,因为 Numba 的目标是编译即使不理想也仍然有效的代码。例如,在测试 operator.eq
时:
if x == None: # Valid code, even if the recommended form is `if x is None:`
这测试了 Numba 对与 None
比较的编译,因此不应更改,即使大多数样式检查器会建议更改。
这项政策已由核心开发者采纳,旨在最大限度地利用有限的资源。虽然拥有一个极其整洁的代码库会很棒,但优先级是修正和功能,而不是代码格式更改。
编码约定
所有 Python 代码都应遵循 PEP 8。我们的 C 代码没有明确定义的编码风格(遵循 PEP 7 会更好吗?)。代码和文档通常应保持在 80 列以内,以确保所有现有工具(如代码审查 UI)的最大可读性。
Numba 使用 Flake8 来确保整个项目中的 Python 代码格式一致。flake8
可以通过 pip
或 conda
安装,然后从 Numba 仓库的根目录运行:
flake8 numba
您可以选择设置 pre-commit 钩子,以便在您进行 git 提交时自动运行 flake8
。这可以通过安装 pre-commit
来完成:
pip install pre-commit
然后从 Numba 仓库的根目录运行:
pre-commit install
现在,每次您提交更改时都会运行 flake8
。您可以使用 git commit --no-verify
跳过此检查。
Numba 已开始在其代码库中使用 类型提示。这将是一个逐步增加使用类型提示的文件数量,以及从自愿到强制要求新功能使用类型提示的过程。Mypy 用于自动化静态检查。
目前,只有某些文件会受到 mypy 检查。列表可以在 mypy.ini
中找到。更改这些文件时,需要添加所需的类型提示,以使 mypy 测试通过。只有在特殊情况下才应使用 type: ignore
注释。
如果您正在贡献新功能,我们鼓励您使用类型提示,即使该文件当前不在检查列表中。如果您想贡献类型提示以使新文件加入检查列表,请将文件添加到 mypy.ini
中的 files
变量中,并决定您要达到的合规级别。级别 3 是基本静态检查,而级别 2 和 1 代表更严格的检查。这些级别在 mypy.ini
中有详细描述。
Numba 模块 typing
和用于类型提示的 Python 内置模块 typing
之间,以及 Numba 类型(如 Dict
或 Literal
)与同名的 typing
类型之间,存在潜在的混淆。为降低混淆风险,我们使用命名约定,将内置 typing
模块的对象导入时添加 pt
前缀。例如,typing.Dict
导入为 from typing import Dict as ptDict
。
发布说明
添加了重要面向用户修改的拉取请求可能需要在发布说明中提及。要添加发布说明,需要创建一个简短的 .rst
文件,其中包含更改的摘要,并将其放置在 docs/upcoming_changes
中。文件 docs/upcoming_changes/README.rst
详细说明了格式和文件命名约定。
稳定性
仓库的 main
分支应始终保持稳定。这意味着测试套件在所有受支持的平台上(见下文)都能通过且无错误。这也意味着拉取请求在合并之前也需要通过测试套件。
平台支持
每次提交到主分支的代码都会在 Numba 支持的所有平台上自动测试。这包括 ARMv8 和 NVIDIA GPU。然而,构建系统是 Anaconda 内部的,因此我们也使用 Azure 提供尽可能多的公共持续集成信息,以支持该服务。Azure CI 会自动测试所有 Windows、OS X 和 Linux 上的拉取请求,以及不同 Python 和 NumPy 版本的抽样。如果您在不熟悉的平台上遇到问题,请随时在您的拉取请求中寻求帮助。Numba 核心开发人员可以帮助诊断跨平台兼容性问题。另请参阅 持续集成 部分,了解公共 CI 的实现方式。
持续集成测试
Numba 测试套件给 CI 系统带来了很多麻烦:
它非常庞大,有 9000 多个测试。
部分由于第 1 点以及编译器涉及的复杂性,测试套件运行时间很长。
测试套件中有一些部分是故意设计来将系统压力推到接近崩溃的程度(例如并发编译和执行,使用线程和 fork 进程的测试)。
Numba 必须测试的组合数量远远超过任何公共 CI 系统的容量(Python 版本 x NumPy 版本 x 操作系统 x 架构 x 特性库(例如 SVML)x 线程后端(例如 OpenMP、TBB)),此外还有 CUDA 及其各种版本。
由于上述原因,公共 CI 的实现如下:
测试矩阵中操作系统 x Python x NumPy x 各项功能的组合旨在提供一个良好的指示性结果,判断“此拉取请求可能没问题”。
当公共 CI 运行时,它会:
查找包含已更改测试的文件,并对整个测试矩阵运行这些测试。
在测试矩阵的每个部分运行测试套件的一个子集。即将测试套件按测试矩阵中的组合数量切片,每个组合运行一个块。这样做是为了提高速度,否则公共 CI 无法应对负载。
如果拉取请求(PR)更改了 CUDA 代码或将影响 CUDA 目标,则需要在 gpuCI 上运行。Numba 维护者可以在 PR 讨论中评论 run gpuCI tests
来触发此操作。这将在 Linux 上使用各种 CUDA 工具包版本运行 CUDA 测试套件,以提供对更改在 CUDA 方面正确性的一些初步信心。获得批准后,PR 也将在 Numba 的构建场上运行,以测试其他 CUDA 配置(包括 gpuCI 未测试的 Windows)。
如果 PR 与 CUDA 无关,但对核心开发者认为有风险的部分进行了更改,那么它也将在 Numba 农场上运行,以确保万无一失。Numba 项目的私人构建和测试农场实际上会在真实硬件上执行所有适用的测试以及上述所有组合!
类型注解和运行时类型检查
Numba 正在慢慢增加类型注解。为了方便审查逐步添加类型注解的拉取请求,测试套件使用 typeguard 执行运行时类型检查。这有助于验证类型注解的有效性。
要在测试套件中启用运行时类型检查,用户可以使用源代码根目录中的 runtests.py 作为测试运行器,并设置环境变量 NUMBA_USE_TYPEGUARD=1
。例如:
$ NUMBA_USE_TYPEGUARD=1 python runtests.py numba.tests
有助于拉取请求的事项
即使有了上述缓解设计,公共 CI 仍然可能超载,导致构建积压。因此,在打开拉取请求时,限制推送更改的频率非常有帮助。理想情况下,请压缩提交以减少补丁数量和/或尽可能不频繁地推送。此外,一旦拉取请求审查开始,请不要变基/强制推送/压缩或做任何会重写已审查代码历史的操作,因为 GitHub 无法跟踪这些操作,这使得审查人员很难看到发生了什么变化。
核心开发人员感谢大家在此方面的合作!
文档
Numba 文档分为两个仓库:
此文档位于 Numba 仓库内的
docs
目录中。Numba 主页的源代码位于另一个仓库:https://github.com/numba/numba.github.com。
主文档
此文档位于 Numba 仓库的 docs
目录下。它使用 Sphinx、numpydoc 和 sphinx-rtd-theme 构建。
要安装所有构建文档所需的依赖项,请使用:
$ conda install sphinx numpydoc sphinx_rtd_theme
您可以编辑 docs/source/
下的源文件,之后您可以在 docs/
下构建和检查文档:
$ make html
$ open _build/html/index.html
网站主页
Numba 主页 https://numba.pydata.org.cn 可在此处获取:https://github.com/numba/numba.github.com