为 Numba 贡献

我们欢迎任何想要为 Numba 做出贡献的人,无论贡献大小!即使是简单的文档改进也非常鼓励。如果你有问题,不要犹豫,尽管提问(见下文)。

通信

实时聊天

Numba 使用 Gitter 进行公开的实时聊天。为了帮助提高信噪比,我们有两个频道:

两个频道都是公开的,但我们可能会要求将 numba-dev 上的讨论转移到 numba 频道。这样做只是为了确保 numba-dev 对核心开发者来说易于跟进。

请注意,Github 问题跟踪器是报告错误的最佳地点。聊天中的错误报告难以跟踪,并且很可能会丢失。

论坛

Numba 使用 Discourse 作为论坛,用于较长时间的讨论,如设计讨论和路线图规划。有各种类别可供选择,可以通过以下链接访问:numba.discourse.group

每周会议

Numba的核心开发者每周都会举行一次视频会议,讨论路线图、功能规划和未解决的问题。这些会议是完全公开的,详情发布在 numba.discourse.group 公告 上,欢迎所有人加入讨论。会议记录将被整理并发布到 Numba wiki 上。

Bug 追踪器

我们使用 Github issue tracker 来追踪错误报告和功能请求。如果您报告问题,请包括具体细节:

  • 你正在尝试做的事情;

  • 您使用的是哪个操作系统以及您正在运行的 Numba 版本;

  • Numba 是如何表现异常的,例如完整的错误回溯,或者你得到的不预期的结果;

  • 尽可能地,提供一个允许完全重现您问题的代码片段。

开始设置

如果你想贡献代码,我们建议你先 fork 我们的 Github 仓库,然后创建一个代表你工作的分支。当你的工作准备好后,你应该通过 Github 界面提交一个拉取请求。

如果你想,即使工作尚未完成,你也可以提交一个拉取请求。这可以用来收集反馈,或者在 持续集成 平台上测试你的更改。在这种情况下,请在你的拉取请求标题前加上 [WIP]

构建环境

Numba 有许多依赖项(主要是 NumPyllvmlite),这些依赖项的构建指令并不简单。除非你想自己构建这些依赖项,我们建议你使用 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:

$ git clone git@github.com:numba/numba.git
$ cd numba
$ python setup.py build_ext --inplace

这假设您的开发系统上有一个可用的C编译器和运行时。每当你修改Numba源代码树中的C文件时,你都需要再次运行此命令。

Numba 的 setup 中的 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 可以通过 pipconda 安装,然后从 Numba 仓库的根目录运行:

flake8 numba

可选地,您可能希望设置 pre-commit hooks 以便在您进行 git 提交时自动运行 flake8。这可以通过安装 pre-commit 来完成:

pip install pre-commit

然后运行:

pre-commit install

从 Numba 仓库的根目录开始。现在每次提交更改时都会运行 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 类型(如 DictLiteral)与同名的 typing 类型之间存在混淆的潜在风险。为了降低混淆的风险,我们采用了一种命名约定,即内置 typing 模块的对象以 pt 前缀导入。例如,typing.Dict 被导入为 from typing import Dict as ptDict

发行说明

添加了重要用户界面修改的 Pull Requests 可能需要在发布说明中提及。要添加发布说明,需要创建一个包含更改摘要的简短 .rst 文件,并将其放置在 docs/upcoming_changes 中。文件 docs/upcoming_changes/README.rst 详细说明了格式和文件命名约定。

稳定性

仓库的 main 分支预计在任何时候都是稳定的。这意味着在所有支持的平台上,测试套件都能无错误地通过(见下文)。这也意味着在合并之前,拉取请求也需要通过测试套件。

平台支持

对主分支的每一次提交都会在 Numba 支持的所有平台上自动进行测试。这包括 ARMv8、POWER8 和 NVIDIA GPU。然而,构建系统是 Anaconda 内部的,因此我们还使用 Azure 为尽可能多的组合提供公共持续集成信息。Azure CI 自动测试所有拉取请求在 Windows、OS X 和 Linux 上的情况,以及不同 Python 和 NumPy 版本的采样。如果你在不熟悉的平台上遇到问题,欢迎在你的拉取请求中寻求帮助。Numba 的核心开发者可以帮助诊断跨平台兼容性问题。另请参阅 持续集成 部分,了解公共 CI 的实现方式。

持续集成测试

Numba 测试套件给 CI 系统带来了许多麻烦:

  1. 它非常庞大,超过9000个测试。

  2. 部分由于1. 和编译器相当复杂,测试套件运行需要很长时间。

  3. 测试套件中有部分内容是特意设计来对系统施加压力,几乎达到故障点的(例如同时使用线程和分叉进程进行并发编译和执行的测试)。

  4. Numba 需要测试的组合远远超出了任何公共 CI 系统的容量,(Python 版本 x NumPy 版本 x 操作系统 x 架构 x 功能库(例如 SVML)x 线程后端(例如 OpenMP、TBB)),然后还有 CUDA 及其所有版本变体。

因此,公共CI的实现如下:

  1. 测试矩阵中操作系统 x Python x NumPy x 各种功能的组合旨在给出“这个拉取请求可能没问题”的良好指示性结果。

  2. 当公共CI运行时:

    1. 查找包含被提议更改所修改的测试的文件,并在整个测试矩阵上运行这些测试。

    2. 在测试矩阵的每个部分上运行测试套件的一个子集。即,根据测试矩阵中的组合数量对测试套件进行切片,每个组合运行一个块。这样做是为了加快速度,因为公共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 是一个开源项目,与许多类似项目一样,它资源有限。因此,核心开发者不得不为问题/拉取请求(PR)分配优先级。帮助项目其他部分以腾出核心开发者时间,是提高您的问题/PR优先级的绝佳方式。帮助的方式包括:

  • 对PR进行初步审查。这通常不需要编译器工程知识,只需检查所提议的补丁是否质量良好,修复了问题/实现了功能,并且经过了良好的测试和文档化。

  • 调试一个问题,有许多 “需要分类” 的问题,这基本上涉及调试报告的问题。即使你不能完全解决问题,为其他人留下关于发现的内容的笔记也是有帮助的。

  • discourse 和/或 gitter.im 上回答用户问题/提供帮助。

核心开发者感谢大家对上述内容的理解!

文档

Numba 文档分布在两个仓库中:

主文档

本文档位于 Numba 仓库docs 目录下。它使用 Sphinxnumpydocsphinx-rtd-theme 构建。

要安装构建文档所需的所有依赖项,请使用:

$ conda install sphinx numpydoc sphinx_rtd_theme

你可以在 docs/source/ 下编辑源文件,之后可以在 docs/ 下构建并检查文档:

$ make html
$ open _build/html/index.html

网站首页

Numba 的主页在 https://numba.pydata.org 可以从这里获取:https://github.com/numba/numba.github.com