原文:
numpy.org/doc/
高级调试工具
原文:
numpy.org/doc/1.26/dev/development_advanced_debugging.html#
如果您到达这里,您想深入使用更高级的工具。这通常对于首次贡献者和日常开发来说并不需要。这些通常很少使用,例如接近新的 NumPy 发布时,或者进行了大型或特别复杂的更改时。
由于这些工具不是在常规基础上使用,且仅在某些系统上可用,请预期差异、问题或特异行为;如果您遇到困难,我们将乐意帮助,并感激对这些工作流程的任何改进或建议。
使用额外工具找到 C 错误
大多数开发不需要超过 调试 中显示的典型调试工具链。但例如,内存泄漏可能特别微妙或难以缩小范围。
我们不希望大多数贡献者运行这些工具中的任何一个。但是,您可以确保我们更容易地追踪此类问题:
- 测试应该覆盖所有代码路径,包括错误路径。
- 尽量编写简短且简单的测试。如果您有一个非常复杂的测试,请考虑创建一个额外的简单测试。这可能会有帮助,因为通常只有找到触发问题的测试而不是测试哪一行容易。
- 如果数据被读取/使用,千万不要使用
np.empty
。valgrind
会注意到这一点并报告错误。当您不关心数值时,可以代替生成随机数值。
这会帮助我们在您的更改发布之前捕捉任何疏忽,并且意味着您不必担心制造参考计数错误,这可能令人望而却步。
Python 调试版本
Python 的调试构建在 Linux 系统上通常通过系统包管理器轻松可用,但也可以在其他平台上使用,可能是在不太方便的格式中。如果您无法从系统包管理器轻松安装 Python 的调试构建,您可以使用 pyenv 自行构建。例如,要安装并全局激活 Python 3.10.8 的调试构建,您可以执行:
代码语言:javascript复制pyenv install -g 3.10.8
pyenv global 3.10.8
请注意,pyenv install
通过源代码构建 Python,所以在构建之前,您必须确保安装了 Python 的依赖项,请参阅 pyenv 文档获取平台特定的安装说明。您可以使用 pip
安装调试会话中可能需要的 Python 依赖项。如果 pypi 上没有调试版的依赖包,您将需要从源代码构建依赖项,并确保您的依赖项也被编译为调试版本。
Python 的调试构建通常将 Python 可执行文件命名为 pythond
而不是 python
。要检查是否安装了 Python 的调试构建,您可以运行,例如 pythond -m sysconfig
以获取 Python 可执行文件的构建配置。调试构建将使用 CFLAGS
中的调试编译器选项构建(例如 -g -Og
)。
运行 Numpy 测试或交互式终端通常很简单:
代码语言:javascript复制python3.8d runtests.py
# or
python3.8d runtests.py --ipython
并且已经在调试中提到。
Python 调试版本将有助于:
寻找可能导致随机行为的错误。一个例子是对象在被删除后仍然被使用。
Python 调试版本允许检查正确的引用计数。这通过使用以下附加命令实现:
代码语言:javascript复制sys.gettotalrefcount()
sys.getallocatedblocks()
Python 调试版本允许使用 gdb 和其他 C 调试器更容易进行调试。
与pytest
一起使用
仅使用调试版本的 Python 运行测试套件不会自行发现许多错误。 Python 的调试版本的另一个优点是它允许检测内存泄漏。
一个更方便的工具是pytest-leaks,可以使用pip
安装。不幸的是,pytest
本身可能会泄漏内存,但通常(目前)通过删除可以取得良好的结果:
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
monkeypatch.setenv('PYTHONHASHSEED', '0')
来自numpy/conftest.py
(这可能随着新的pytest-leaks
版本或pytest
更新而更改)。
这使得可以方便地运行测试套件的一部分:
代码语言:javascript复制python3.8d runtests.py -t numpy/core/tests/test_multiarray.py -- -R2:3 -s
其中-R2:3
是pytest-leaks
命令(请参阅其文档),-s
会导致输出打印,并且可能是必要的(在某些版本中,捕获的输出被检测为泄漏)。
请注意,一些测试已知(甚至是设计上)会泄漏引用,我们试图标记它们,但可能会出现一些误报。
valgrind
Valgrind 是一个强大的工具,用于查找某些内存访问问题,应该在复杂的 C 代码上运行。基本使用valgrind
通常不需要更多:
PYTHONMALLOC=malloc valgrind python runtests.py
其中PYTHONMALLOC=malloc
是必需的,以避免 Python 本身产生误报。根据系统和 valgrind 版本的不同,您可能会看到更多的误报。valgrind
支持“抑制”以忽略其中的一些,Python 也有一个抑制文件(甚至有一个编译时选项),如果发现有必要的话可能会有所帮助。
Valgrind 有助于:
查找未初始化变量/内存的使用。
检测内存访问违规(读取或写入已分配内存之外的区域)。
发现许多内存泄漏。请注意,对于大多数泄漏,Python 调试构建方法(以及pytest-leaks
)更加敏感。原因是valgrind
只能检测内存是否确实丢失。如果:
dtype = np.dtype(np.int64)
arr.astype(dtype=dtype)
对dtype
的引用计数不正确,这是一个 bug,但 valgrind 不能看到它,因为np.dtype(np.int64)
总是返回相同的对象。然而,并非所有的 dtypes 都是单例,因此这可能会导致不同输入泄漏内存。在某些罕见情况下,NumPy 使用malloc
而不是 Python 内存分配器,这对 Python 调试构建是不可见的。通常应避免使用malloc
,但也有一些例外情况(例如PyArray_Dims
结构是公共 API,不能使用 Python 分配器)。
尽管使用 valgrind 进行内存泄漏检测速度慢且不够敏感,但却很方便:您可以在不修改大多数程序的情况下使用 valgrind 运行它们。
需要注意的事项:
- Valgrind 不支持 numpy 的
longdouble
,这意味着测试将失败或被标记为完全正常的错误。 - 在运行 NumPy 代码之前和之后预计会有一些错误。
- 缓存可能意味着错误(特别是内存泄漏)可能无法检测到,或者只在以后的不相关时间检测到。
valgrind 的一个巨大优势是,除了 valgrind 本身外,它几乎没有其他要求(尽管你可能希望使用调试构建来获得更好的回溯)。
与pytest
一起使用
您可以使用 valgrind 运行测试套件,当您只对部分测试感兴趣时,这可能就足够了:
代码语言:javascript复制PYTHOMMALLOC=malloc valgrind python runtests.py
-t numpy/core/tests/test_multiarray.py -- --continue-on-collection-errors
注意--continue-on-collection-errors
,这是目前必需的,因为缺少longdouble
支持导致失败(如果不运行完整的测试套件,通常不需要这样做)。
如果您希望检测内存泄漏,您还将需要--show-leak-kinds=definite
和可能更多的 valgrind 选项。就像pytest-leaks
一样,某些测试已知会导致 valgrind 中的泄漏错误,可能会被标记为这样。
我们开发了pytest-valgrind,它:
- 分别为每个测试报告错误
- 将内存泄漏缩小到单个测试(默认情况下,valgrind 仅在程序停止后检查内存泄漏,这非常麻烦)。
请参考其README
获取更多信息(其中包括一个针对 NumPy 的示例命令)。
使用额外的工具找到 C 错误
大多数开发不需要超出典型的调试工具链,如调试所示。但例如,内存泄漏可能特别微妙或难以缩小范围。
我们不希望大多数贡献者运行其中的任何工具。但是,您可以确保我们可以更轻松地跟踪此类问题:
- 测试应覆盖所有代码路径,包括错误路径。
- 尽量编写简短和简单的测试。如果您有非常复杂的测试,请考虑创建额外的简单测试。这可能会有所帮助,因为通常只有找到触发问题的测试而不是测试的哪一行是容易的。
- 如果读取/使用数据,则永远不要使用
np.empty
。valgrind
会注意到这一点并报告错误。当您不关心值时,您可以生成随机值。
这将帮助我们在您的更改发布之前捕捉任何疏忽,并且意味着您不必担心制作参考计数错误,这可能会令人畏惧。
Python 调试构建
Python 的调试构建很容易在 Linux 系统的系统包管理器中提供,但也可以在其他平台上获得,可能是以不太方便的格式。如果您无法轻松地从系统包管理器安装 Python 的调试构建,您可以使用pyenv自行构建。例如,要安装并全局激活 Python 3.10.8 的调试构建,可以执行:
代码语言:javascript复制pyenv install -g 3.10.8
pyenv global 3.10.8
请注意,pyenv install
会从源代码构建 Python,因此在构建之前必须确保 Python 的依赖项已经安装了,查看 pyenv 的文档以获取特定平台的安装说明。您可以使用 pip
安装您的调试会话可能需要的 Python 依赖项。如果 pypi 上没有调试版的依赖包,你需要从源代码构建这些依赖项,并确保你的依赖项也编译为调试版本。
通常,Python 的调试版本会将 Python 可执行文件命名为pythond
而不是 python
。要检查是否安装了 Python 的调试版本,可以运行例如 pythond -m sysconfig
来获取 Python 可执行文件的构建配置。调试版本将使用 CFLAGS
中的调试编译器选项构建(例如 -g -Og
)。
运行 Numpy 测试或交互式终端通常也很容易:
代码语言:javascript复制python3.8d runtests.py
# or
python3.8d runtests.py --ipython
并且已经在 Debugging 中提到过。
Python 的调试版本将有所帮助:
找到可能导致随机行为的错误。一个例子是在对象被删除后仍然被使用。
Python 的调试版本允许检查正确的引用计数。这可以使用以下额外命令:
代码语言:javascript复制sys.gettotalrefcount()
sys.getallocatedblocks()
Python 的调试版本允许使用 gdb 和其他 C 调试器更容易地进行调试。
与 pytest
一起使用
仅使用调试版的 Python 运行测试套件本身并不会找到很多错误。调试版本的 Python 的另一个优点是它允许检测内存泄漏。
一个使这件事更容易的工具是 pytest-leaks,可以使用 pip
安装。不幸的是,pytest
本身可能会泄漏内存,但通常(目前)可以通过移除来取得良好的结果:
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
monkeypatch.setenv('PYTHONHASHSEED', '0')
来自 numpy/conftest.py
(这可能会随着新的 pytest-leaks
版本或 pytest
更新而改变)。
这允许方便地运行测试套件,或其中的一部分:
代码语言:javascript复制python3.8d runtests.py -t numpy/core/tests/test_multiarray.py -- -R2:3 -s
其中 -R2:3
是 pytest-leaks
命令(参见其文档),-s
会导致输出打印并可能是必要的(在一些版本中,捕获的输出被检测为泄漏)。
请注意,一些测试已知(甚至是设计的)会泄漏引用,我们试图标记它们,但还是会有一些误报。
valgrind
Valgrind 是一个强大的工具,可以找到某些内存访问问题,并且应该在复杂的 C 代码上运行。valgrind
的基本用法通常不需要更多的操作:
PYTHONMALLOC=malloc valgrind python runtests.py
其中,PYTHONMALLOC=malloc
在避免 Python 内部误报时是必要的。根据系统和 valgrind 版本的不同,可能会看到更多的误报。 valgrind
支持“抑制”来忽略其中一些,Python 确实有一个抑制文件(甚至有一个编译时选项),这可能会在必要时有所帮助。
Valgrind 有助于:
查找未初始化的变量/内存的使用。
检测内存访问违例(从已分配的内存之外读取或写入)。
发现许多内存泄漏。请注意,大多数泄漏对于 python 调试构建方法(以及pytest-leaks
)都更为敏感。原因是valgrind
只能检测内存是否确实丢失。如果:
dtype = np.dtype(np.int64)
arr.astype(dtype=dtype)
对于dtype
的引用计数不正确,这是一个 bug,但 valgrind 无法看到它,因为np.dtype(np.int64)
总是返回相同的对象。然而,并非所有的 dtypes 都是单例,所以这可能会导致不同输入的内存泄漏。在罕见的情况下,NumPy 使用malloc
而不是 Python 内存分配器,这对 Python 调试构建是不可见的。通常应该避免使用malloc
,但也有一些例外情况(例如,PyArray_Dims
结构是公共 API,不能使用 Python 的分配器)。
即使 valgrind 用于内存泄漏检测很慢且不太敏感,它也可能是方便的:你可以在不修改大多数程序的情况下运行 valgrind。
需要注意的事项:
- Valgrind 不支持 numpy 的
longdouble
,这意味着测试将失败或被标记为完全正常的错误。 - 在运行 NumPy 代码之前和之后,预计会出现一些错误。
- 缓存可能意味着错误(特别是内存泄漏)可能无法检测出,或者只能在以后无关的时间检测出。
valgrind 的一个很大优势是除了 valgrind 本身外没有其他要求(虽然你可能希望使用调试构建获得更好的回溯)。
与pytest
一起使用
可以使用 valgrind 运行测试套件,当你只对其中几个测试感兴趣时,这可能足够了:
代码语言:javascript复制PYTHOMMALLOC=malloc valgrind python runtests.py
-t numpy/core/tests/test_multiarray.py -- --continue-on-collection-errors
注意--continue-on-collection-errors
,因为缺少longdouble
支持导致失败,目前这是必需的(如果不运行完整的测试套件,则通常不需要这样做)。
如果你希望检测内存泄漏,还需要--show-leak-kinds=definite
以及可能更多的 valgrind 选项。就像pytest-leaks
一样,某些测试已知会在 valgrind 中泄漏导致错误,可能标记为这样也可能不会。
我们开发了pytest-valgrind,它:
- 报告每个测试的错误
- 将内存泄漏限制在单个测试中(默认情况下,valgrind 仅在程序停止后检查内存泄漏,这非常麻烦)。
请参考其README
获取更多信息(其中包括 NumPy 的示例命令)。
Python 调试构建
调试构建的 Python 很容易通过 Linux 系统上的系统包管理器等方式获得,但它也可以在其他平台上以不太方便的格式获得。如果不能轻松地从系统包管理器安装 Python 的调试构建,则可以使用pyenv自行构建一个。例如,要安装并全局激活 Python 3.10.8 的调试构建,可以执行以下操作:
代码语言:javascript复制pyenv install -g 3.10.8
pyenv global 3.10.8
注意,pyenv install
是根据源码构建 Python 的,因此在构建之前必须确保已安装 Python 的依赖项,请参阅 pyenv 文档中特定平台的安装说明。您可以使用pip
安装您在调试会话中可能需要的 Python 依赖项。如果在pypi上没有调试版本的 wheel 可用,则需要从源代码构建依赖项,并确保您的依赖项也以调试构建。
通常,Python 的调试构建将 Python 可执行文件命名为pythond
而不是python
。要检查是否安装了 Python 的调试版本,您可以运行例如pythond -m sysconfig
以获取 Python 可执行文件的构建配置。调试构建将使用CFLAGS
中的调试编译器选项构建(例如-g -Og
)。
运行 Numpy 测试或者交互式终端通常非常简单:
代码语言:javascript复制python3.8d runtests.py
# or
python3.8d runtests.py --ipython
并且已经在调试中提到过。
Python 调试构建将有所帮助:
查找可能导致随机行为的错误。一个例子是在某个对象被删除后仍然使用它。
Python 调试构建可以检查正确的引用计数。这可以���用附加命令来实现:
代码语言:javascript复制sys.gettotalrefcount()
sys.getallocatedblocks()
Python 调试构建可以更轻松地使用 gdb 和其他 C 调试器进行调试。
与pytest
一起使用
只使用调试版的 python 构建来运行测试套件本身不会发现太多错误。Python 调试版本的另一个好处是可以检测内存泄漏。
一个工具可以帮助简化此过程是pytest-leaks,可以使用pip
进行安装。不幸的是,pytest
本身可能会发生内存泄漏,但通常(当前版本)可以通过移除以下内容来取得良好的结果:
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
monkeypatch.setenv('PYTHONHASHSEED', '0')
来自numpy/conftest.py
(这可能会随着新的pytest-leaks
版本或pytest
更新而改变)。
这样可以方便地运行测试套件或其中的一部分:
代码语言:javascript复制python3.8d runtests.py -t numpy/core/tests/test_multiarray.py -- -R2:3 -s
其中-R2:3
是pytest-leaks
命令(参见其文档),-s
导致输出打印并且可能是必要的(在某些版本中,捕获的输出被检测为泄漏)。
请注意,一些测试已知(甚至是设定)会泄漏引用,我们尝试对其进行标记,但可能会有一些误报。
与pytest
一起使用
只使用调试版的 python 构建来运行测试套件本身不会发现太多错误。Python 调试版本的另一个好处是可以检测内存泄漏。
可以使用pytest-leaks来简化这个过程,可以使用pip
进行安装。不幸的是,pytest
本身可能会发生内存泄漏,但通常(当前版本)可以通过移除以下内容来取得良好的结果:
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
monkeypatch.setenv('PYTHONHASHSEED', '0')
来自numpy/conftest.py
(这可能会随着新的pytest-leaks
版本或pytest
更新而改变)。
这样可以方便地运行测试套件或其中的一部分:
代码语言:javascript复制python3.8d runtests.py -t numpy/core/tests/test_multiarray.py -- -R2:3 -s
其中-R2:3
是pytest-leaks
命令(参见其文档),-s
导致输出打印并且可能是必要的(在某些版本中,捕获的输出被检测为泄漏)。
请注意,有些测试已知(或者甚至是特意设计)会泄漏引用,我们尽量做了标记,但预计会出现一些误报。
valgrind
Valgrind 是一个强大的工具,可以找出某些内存访问问题,应该在复杂的 C 代码上运行。基本使用valgrind
通常不需要超过:
PYTHONMALLOC=malloc valgrind python runtests.py
在某些系统和 valgrind 版本中,PYTHONMALLOC=malloc
是必要的,以避免来自 python 本身的误报。valgrind
支持“抑制”来忽略其中一些,Python 确实有一个抑制文件(甚至是一个编译时选项),这可能有助于你是否发现它是必要的。
Valgrind 有助于:
发现未初始化的变量/内存的使用。
检测内存访问违规(读取或写入已分配内存之外的位置)。
发现许多内存泄漏。请注意,对于大多数泄漏,python 调试构建方法(和pytest-leaks
)更为敏感。原因是valgrind
只能检测内存是否绝对丢失。如果:
dtype = np.dtype(np.int64)
arr.astype(dtype=dtype)
对于dtype
的引用计数不正确,这是一个错误,但是 valgrind 无法看到它,因为np.dtype(np.int64)
总是返回相同的对象。然而,并不是所有的 dtypes 都是单例的,所以这可能会导致不同输入的内存泄漏。在罕见的情况下,NumPy 使用malloc
而不是对 Python 内存分配器进行调试构建,这些对于 Python 调试构建是不可见的。通常应该避免使用malloc
,但也有一些例外情况(例如PyArray_Dims
结构是公共 API,不能使用 Python 分配器)。
即使使用 valgrind 进行内存泄漏检测是缓慢且不敏感的,但它可能是方便的:你可以在大多数程序上运行 valgrind 而无需修改。
需要注意的事项:
- valgrind 不支持 numpy 的
longdouble
,这意味着测试将失败或被标记为完全正常的错误。 - 在运行 NumPy 代码之前和之后,都可以期待一些错误。
- 缓存可能意味着错误(特别是内存泄漏)可能不会被检测到,或者只会在以后的不相关时间发现。
Valgrind 的一个很大优势是除了 valgrind 本身以外没有任何要求(尽管你可能希望使用调试构建以获得更好的回溯)。
与pytest
一起使用
你可以用 valgrind 运行测试套件,当你只对其中一些测试感兴趣时,这可能足够了:
代码语言:javascript复制PYTHOMMALLOC=malloc valgrind python runtests.py
-t numpy/core/tests/test_multiarray.py -- --continue-on-collection-errors
请注意--continue-on-collection-errors
,目前由于缺少longdouble
支持导致失败(如果你不运行完整的测试套件,通常不需要这样做)。
如果你希望检测内存泄漏,你还需要--show-leak-kinds=definite
和可能更多的 valgrind 选项。就像对于pytest-leaks
,某些测试已知会泄露导致 valgrind 错误,可能会标记或可能不会标记。
我们开发了pytest-valgrind,它:
- 对每个测试单独报告错误
- 将内存泄漏问题缩小到单个测试(默认情况下,valgrind 仅在程序停止后检测内存泄漏,这非常麻烦)。
更多信息请参阅其README
(其中包含了一个 NumPy 的示例命令)。
与pytest
一起使用
您可以使用 valgrind 运行测试套件,这在您只对少数测试感兴趣时可能足够:
代码语言:javascript复制PYTHOMMALLOC=malloc valgrind python runtests.py
-t numpy/core/tests/test_multiarray.py -- --continue-on-collection-errors
请注意--continue-on-collection-errors
,这是由于缺少对longdouble
的支持导致失败的临时解决方案(如果您不运行完整的测试套件,通常不需要此选项)。
如果您希望检测内存泄漏,您还需要--show-leak-kinds=definite
和可能更多的 valgrind 选项。就像pytest-leaks
一样,某些测试已知在 valgrind 中引起泄漏并可能标记为此类错误。
我们开发了 pytest-valgrind 它:
- 针对每个测试单独报告错误
- 将内存泄漏问题缩小到单个测试(默认情况下,valgrind 仅在程序停止后检测内存泄漏,这非常麻烦)。
更多信息请参阅其README
(其中包含了一个 NumPy 的示例命令)。
评审员指南
原文:
numpy.org/doc/1.26/dev/reviewer_guidelines.html
评审未完成的拉取请求(PR)有助于推动项目向前发展。我们也鼓励项目之外的人参与进来;这是熟悉代码库的好方法。
谁可以成为评审员?
评审可以来自 NumPy 团队之外 - 我们欢迎来自领域专家(例如 linalg 或 fft)或其他项目维护者的贡献。你不需要是 NumPy 维护者(具有合并 PR 权限的 NumPy 团队成员)才能进行评审。
如果我们还不认识你,请在邮件列表或 Slack中介绍自己,然后再开始评审拉取请求。
交流指南
- 每一个 PR,无论好坏,都是一种慷慨的行为。以积极的评论开篇将有助于作者感到受到了奖励,你后续的评论可能会被更清晰地听到。你也会感觉良好。
- 如果可能的话,从大的问题开始,这样作者就知道它们已经被理解了。抵制立即逐行查看或以小型普遍问题开头的诱惑。
- 你是项目的代表,而 NumPy 在一段时间前决定了它将成为何种项目:开放、富有同理心、欢迎、友好和耐心。对贡献者要友善。
- 不要让完美成为好的敌人,特别是对于文档。如果你发现自己提出了许多小建议,或者对样式或语法过于吹毛求疵,请考虑在解决所有重要问题后合并当前的 PR。然后,要么直接推送一个提交(如果你是维护者),要么自己开启一个跟进 PR。
- 如果你在评审回复中需要帮助,请查看一些标准回复。
评审员清单
- 在所有条件下,预期行为是否清晰?一些需要注意的事项:
- 对于意外输入,如空数组或 nan/inf 值,会发生什么?
- 是否测试了轴或形状参数是 int 还是 tuples?
- 如果一个函数支持那些不寻常的 dtypes,那么是否测试了它们?
- 变量名称应该改进以提高清晰度或一致性吗?
- 应该添加注释,还是移除那些无用或多余的注释?
- 文档是否遵循了 NumPy 指南?文档字符串是否格式正确?
- 代码是否遵循了 NumPy 的风格指南?
- 如果你是维护者,并且从 PR 描述中不明显,那么在合并消息中添加一个简短的说明,说明分支的作用,如果关闭一个问题,还要添加“Closes gh-123”,其中 123 是问题编号。
- 对于代码更改,至少有一个维护者(即具有提交权限的人)应审查并批准拉取请求。如果您是第一个审查 PR 并同意更改,请使用 GitHub 的 批准审查 工具标记为批准。如果 PR 很简单,例如明显地是正确的 bug 修复,可以立即合并。如果更复杂或更改了公共 API,请将其保持开放至少几天,以便其他维护者有机会审查。
- 如果您是已经批准的 PR 的后续审阅者,请使用与新 PR 相同的审查方法(关注更大的问题,抵制只是加一些琐碎意见的诱惑)。如果您有提交权限并认为不需要进行更多审查,请合并 PR。
对于维护者
- 在合并 PR 之前,请确保所有自动化 CI 测试通过,并且 文档构建 无任何错误。
- 在出现合并冲突时,请要求 PR 提交者在主分支上进行 rebase 操作。
- 对于新增功能或存在某种复杂性的 PR,请在合并之前等待至少一两天。这样,其他人有机会在代码合并之前发表评论。考虑将其添加到发布说明中。
- 在合并贡献时,提交者负责确保这些满足 NumPy 的开发流程准则 中列出的要求。此外,请检查新功能和向后兼容性断裂是否已在 numpy-discussion 邮件列表 上讨论。
- 合并 PR 之前,对于您认为太混乱的 PR,压缩提交或清理提交消息是可以的。在此过程中,请记住保留原始作者的姓名。确保提交消息遵循 NumPy 的规则。
- 当您想要拒绝一个 PR 时:如果非常明显,您可以直接关闭它并解释原因。如果不是,那么首先解释为什么认为该 PR 不适合包含在 NumPy 中,然后让第二个 committer 发表评论或关闭。
- 如果 PR 提交者在 6 个月内未对您的评论作出回应,请将相关 PR 移至带有“inactive”标签的非活跃类别。在这一点上,维护者可以关闭该 PR。如果有兴趣完成正在考虑的 PR,可以随时表示,无需等待 6 个月,只需发表评论即可。
- 鼓励维护者在合并之前进行必要的小改动(例如,修复代码风格或语法错误)。如果某个 PR 变得不活跃,维护者可能会进行较大的更改。请记住,PR 是贡献者与审阅者之间的合作,有时直接推送是完成它的最佳方式。
API 更改
如上所述,大多数公共 API 更改应提前讨论,并经常与更广泛的观众(邮件列表上,甚至通过 NEP)讨论。
对于公共 C-API 的更改,请注意 NumPy C-API 具有向后兼容性,因此任何添加必须与先前版本兼容。如果情况不是这样,必须添加保护。
例如 PyUnicodeScalarObject
结构包含以下内容:
#if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
char *buffer_fmt;
#endif
因为 buffer_fmt
字段是在 NumPy 1.20 中添加到其末尾的(所有先前的字段保持 ABI 兼容性)。同样,numpy/core/code_generators/numpy_api.py
中添加到 API 表中的任何函数必须使用 MinVersion
注释。例如:
'PyDataMem_SetHandler': (304, MinVersion("1.22")),
仅有标题功能(如新的宏)通常无需受到保护。
GitHub 工作流
在审查拉取请求时,请根据需要使用 GitHub 上的工作流跟踪功能:
- 完成审查后,如果您想要请求提交者进行更改,请将您的审查状态更改为“需要更改”。您可以在 GitHub 的 PR 页面上的“文件更改”选项卡中进行此操作,点击右上角的“审查更改”按钮。
- 如果您对当前情况感到满意,请将拉取请求标记为已批准(与更改请求相同方式)。另外(对于维护者):如果您认为准备好合并拉取请求,可直接合并。
在自己的机器上检出拉取请求代码的副本可能会有所帮助,这样您可以在本地测试。您可以使用GitHub CLI通过点击 PR 页面右上角的Open with
按钮来实现这一点。
假设您的开发环境已设置好,现在可以构建代码并进行测试了。
审查的标准回复
可以将其中一些保存在 GitHub 的保存的回复中进行审查:
使用问题
代码语言:javascript复制You are asking a usage question. The issue tracker is for bugs and new features.
I'm going to close this issue, feel free to ask for help via our [help channels](https://numpy.org/gethelp/).
欢迎您更新文档
代码语言:javascript复制Please feel free to offer a pull request updating the documentation if you feel it could be improved.
提供关于 bug 的自包含示例
代码语言:javascript复制Please provide a [self-contained example code](https://stackoverflow.com/help/mcve), including imports and data (if possible), so that other contributors can just run it and reproduce your issue.
Ideally your example code should be minimal.
软件版本
代码语言:javascript复制To help diagnose your issue, please paste the output of:
python -c ‘import numpy; print(numpy.version.version)’
代码语言:javascript复制Thanks.
代码块
代码语言:javascript复制Readability can be greatly improved if you [format](https://help.github.com/articles/creating-and-highlighting-code-blocks/) your code snippets and complete error messages appropriately.
You can edit your issue descriptions and comments at any time to improve readability.
This helps maintainers a lot. Thanks!
链接至代码
代码语言:javascript复制For clarity's sake, you can link to code like [this](https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/).
更好的描述和标题
代码语言:javascript复制Please make the title of the PR more descriptive.
The title will become the commit message when this is merged.
You should state what issue (or PR) it fixes/resolves in the description using the syntax described [here](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword).
需要回归测试
代码语言:javascript复制Please add a [non-regression test](https://en.wikipedia.org/wiki/Non-regression_testing) that would fail at main but pass in this PR.
请勿更改无关内容
代码语言:javascript复制Please do not change unrelated lines. It makes your contribution harder to review and may introduce merge conflicts to other pull requests.
谁可以成为审查人员?
审查可以来自 NumPy 团队之外 - 我们欢迎来自领域专家(例如,linalg 或 fft)或其他项目的维护者的贡献。您不需要成为 NumPy 维护者(拥有合并 PR 权限的 NumPy 团队成员)才能进行审查。
如果我们还不认识您,请考虑在开始审查拉取请求之前在邮件列表或 Slack中介绍自己。
沟通准则
- 每个 PR,无论好坏,都是一种慷慨的行为。以积极的评论开头将帮助作者感到受到奖励,您随后的评论可能会被更清楚地听取。您也会感觉良好。
- 如果可能的话,首先处理重大问题,这样作者就知道它们已被理解。抵制立即逐行查看或以小而普遍的问题开始的诱惑。
- 你是项目的代表,NumPy 在一段时间前决定它将成为的项目类型:开放、有同理心、友好、热情和耐心。对贡献者要友善。
- 不要让完美成为好的敌人,特别是对于文档。如果发现自己提出了许多小建议,或者在样式或语法方面过于吹毛求疵,请考虑在解决所有重要问题后合并当前 PR。然后,要么直接推送一个提交(如果你是维护者),要么自己打开一个后续 PR。
- 如果在审查中需要帮助编写回复,请查看一些用于审阅的标准回复。
审阅者清单
- 所有条件下都清晰地了解预期行为吗?一些需要注意的事项:
- 对于意外输入(如空数组或 nan/inf 值),会发生什么?
- 轴或形状参数是否已经测试过为int或tuple?
- 如果函数支持不寻常的dtypes,是否已经测试过?
- 变量名称是否应当为了明确性或一致性而改进?
- 是否应添加评论,还是删除不必要或多余的评论?
- 文档是否遵循 NumPy 指南?文档字符串是否格式正确?
- 代码是否遵循 NumPy 的风格指南?
- 如果你是一位维护者,并且从 PR 描述中不明显,请在合并消息中添加对分支所做的简短说明,并且,如果关闭了一个问题,请同时添加“Closes gh-123”,其中 123 是问题编号。
- 对于代码更改,至少有一位维护者(即有提交权限的人)应审查并批准拉取请求。如果您是第一个审查 PR 并且同意更改,请使用 GitHub 批准审阅 工具标记。如果 PR 很简单,例如明显正确的错误修复,可以立即合并。如果更复杂或更改了公共 API,请至少保持几天的开放状态,以便其他维护者有机会审查。
- 如果你是已经批准的 PR 的后续审阅者,请使用与新 PR 相同的审阅方法(关注更大的问题,抑制只添加一些微不足道的问题的诱惑)。如果你有提交权限并认为不再需要审查,请合并 PR。
对于维护者
- 在合并 PR 之前,请确保所有自动化 CI 测试都通过,并且文档构建没有任何错误。
- 如果出现合并冲突,请要求 PR 提交者对主干进行变基。
- 对于添加新功能或在某种程度上复杂的 PR,请至少等待一到两天再合并。这样,其他人在代码合并之前有机会发表评论。考虑将其添加到发布说明中。
- 在合并贡献时,提交者负责确保这些符合 NumPy 的开发过程准则的要求。此外,请检查在numpy-discussion 邮件列表上讨论了新功能和向后兼容性的突破。
- 合并您认为太混乱的 PR 的提交或整理提交消息都可以。在执行此操作时,请确保保留原始作者的姓名。确保提交消息遵循 NumPy 的规则。
- 当您想要拒绝一个 PR 时:如果情况非常明显,您可以关闭它并解释原因。如果不是,那么首先解释为什么您认为 PR 不适合包含在 NumPy 中,然后让第二个提交者评论或关闭,这是一个很好的主意。
- 如果 PR 提交者在 6 个月内不回应您的评论,请将相关 PR 移至不活跃类别,并附上“不活跃”标签。此时,维护者可以关闭 PR。如果有任何兴趣完成正在考虑的 PR,则可以随时通过评论指示,无需等待 6 个月。
- 鼓励维护者在合并之前只需要进行小的更改(例如修复代码风格或语法错误)时完成 PR。如果一个 PR 变得不活跃,维护者可以进行较大的更改。请记住,PR 是贡献者与审阅者之间的合作,有时直接推动是完成它的最佳方式。
API 更改
如上所述,大多数公共 API 更改应提前进行讨论,并通常应与更广泛的受众(在邮件列表中,甚至通过 NEP)进行讨论。
对于对公共 C-API 的更改,请注意 NumPy C-API 是向后兼容的,因此任何添加必须与先前版本 ABI 兼容。如果不是这种情况,您必须添加一个保护。
例如PyUnicodeScalarObject
结构包含以下内容:
#if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
char *buffer_fmt;
#endif
因为buffer_fmt
字段在 NumPy 1.20 中添加到其末尾(所有先前字段保持 ABI 兼容)。同样,必须在numpy/core/code_generators/numpy_api.py
中的 API 表中添加函数时使用MinVersion
注释。例如:
'PyDataMem_SetHandler': (304, MinVersion("1.22")),
通常只有头部功能(例如新宏)不需要受到保护。
GitHub 工作流
在审查拉取请求时,请根据需要在 GitHub 上使用工作流跟踪功能:
- 在完成审查后,如果您希望要求提交者进行更改,请将您的审查状态更改为“请求更改”。这可以在 GitHub 的 PR 页面上的“文件更改”选项卡上完成,审查更改(右上角的按钮)。
- 如果您对当前状态感到满意,请将拉取请求标记为已批准(与请求更改相同)。另外(对于维护者):如果您认为它已经准备好合并,请合并拉取请求。
可能对您有帮助的是在自己的计算机上检出拉取请求的代码副本,以便在本地实验。您可以使用GitHub CLI通过单击 PR 页面右上角的“打开方式”按钮来实现这一点。
假设您已经设置好开发环境,现在您可以构建代码并进行测试。
对于维护者
- 确保所有自动化 CI 测试通过才能合并 PR,并且文档构建没有任何错误。
- 在出现合并冲突时,请请求 PR 提交者基于主分支进行变基。
- 对于添加新功能或在某种程度上复杂的 PR,请等待至少一天或两天才合并。这样,其他人有机会在代码合并之前发表评论。考虑将其添加到发布说明中。
- 合并贡献时,提交者负责确保这些符合 NumPy 的开发流程指南。还要检查新功能和向后兼容性破坏是否在numpy-discussion 邮件列表上进行了讨论。
- 合并您认为混乱的 PR 的提交记录或清理提交消息是可以接受的。在此过程中请记得保留原作者的姓名。确保提交消息遵循 NumPy 的规则。
- 当您想要拒绝一个 PR 时:如果非常明显,可以直接关闭并解释原因。如果不够明显,那么先解释为什么您认为这个 PR 不适合包含在 NumPy 中,然后让第二位提交者发表评论或关闭。
- 如果 PR 提交者在 6 个月内没有回复您的评论,请将相关 PR 移动到不活跃类别,并附上“不活跃”标签。此时,维护者可以关闭该 PR。如果有兴趣完成考虑中的 PR,可以通过评论随时表示,而不必等待 6 个月。
- 鼓励维护者在合并之前仅需要进行少量更改(例如修复代码风格或语法错误)即可完成 PR。如果 PR 变得不活跃,维护者可以进行较大的更改。请记住,PR 是贡献者和审阅者之间的协作,有时直接推送是完成 PR 的最佳方式。
API 更改
如上所述,大多数公共 API 更改应提前讨论,通常需要与更广泛的受众(例如邮件列表或甚至通过 NEP)讨论。
对于公共 C-API 的更改,请注意 NumPy C-API 向后兼容,因此任何添加都必须与上一版本的 ABI 兼容。如果不是这种情况,您必须添加保护。
例如PyUnicodeScalarObject
结构包含以下内容:
#if NPY_FEATURE_VERSION >= NPY_1_20_API_VERSION
char *buffer_fmt;
#endif
因为buffer_fmt
字段是在 NumPy 1.20 中添加到其末尾的(所有以前的字段仍然与 ABI 兼容)。同样,任何添加到numpy/core/code_generators/numpy_api.py
中的 API 表的函数必须使用MinVersion
注释。例如:
'PyDataMem_SetHandler': (304, MinVersion("1.22")),
仅包含头文件功能(例如新的宏)通常不需要保护。
GitHub 工作流程
在审查拉取请求时,请在 GitHub 上使用适当的工作流程跟踪功能:
- 在完成审查后,如果您想要要求提交者做出更改,请将您的审查状态更改为“Request changes”。这可以在 GitHub 的 PR 页面,文件更改标签页,审查更改(右上角的按钮)上完成。
- 如果您对当前状态感到满意,请将拉取请求标记为 Approved(与请求更改的方法相同)。此外(对于维护人员):如果认为它已准备好合并,请合并拉取请求。
将拉取请求代码的副本检出到您自己的机器上可能会有所帮助,这样您就可以在本地使用它。您可以使用GitHub CLI通过单击 PR 页面右上角的Open with
按钮来实现这一点。
假设您已经设置好 开发环境,您现在可以构建代码并测试了。
审查的标准回复
将这些保存到 GitHub 的saved replies中可以帮助您进行审查:
使用问题
代码语言:javascript复制You are asking a usage question. The issue tracker is for bugs and new features.
I'm going to close this issue, feel free to ask for help via our [help channels](https://numpy.org/gethelp/).
欢迎您更新文档
代码语言:javascript复制Please feel free to offer a pull request updating the documentation if you feel it could be improved.
用于修复错误的自包含示例
代码语言:javascript复制Please provide a [self-contained example code](https://stackoverflow.com/help/mcve), including imports and data (if possible), so that other contributors can just run it and reproduce your issue.
Ideally your example code should be minimal.
软件版本
代码语言:javascript复制To help diagnose your issue, please paste the output of:
python -c ‘import numpy; print(numpy.version.version)’
代码语言:javascript复制Thanks.
代码块
代码语言:javascript复制Readability can be greatly improved if you [format](https://help.github.com/articles/creating-and-highlighting-code-blocks/) your code snippets and complete error messages appropriately.
You can edit your issue descriptions and comments at any time to improve readability.
This helps maintainers a lot. Thanks!
链接到代码
代码语言:javascript复制For clarity's sake, you can link to code like [this](https://help.github.com/articles/creating-a-permanent-link-to-a-code-snippet/).
更好的描述和标题
代码语言:javascript复制Please make the title of the PR more descriptive.
The title will become the commit message when this is merged.
You should state what issue (or PR) it fixes/resolves in the description using the syntax described [here](https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword).
需要回归测试
代码语言:javascript复制Please add a [non-regression test](https://en.wikipedia.org/wiki/Non-regression_testing) that would fail at main but pass in this PR.
不要更改无关的内容
代码语言:javascript复制Please do not change unrelated lines. It makes your contribution harder to review and may introduce merge conflicts to other pull requests.
NumPy 基准测试
numpy.org/doc/1.26/benchmarking.html
使用 Airspeed Velocity 对 NumPy 进行基准测试。
用法
Airspeed Velocity 可以自行构建和管理 Python 虚拟环境,除非另行指定。要运行基准测试,不需要将 NumPy 的开发版本安装到当前的 Python 环境中。
在开始之前,请确保已安装 airspeed velocity。默认情况下,asv 预先支持 anaconda 和 virtualenv:
代码语言:javascript复制pip install asv
pip install virtualenv
在贡献新的基准后,你应该先在本地测试,然后再提交拉取请求。
要运行所有基准测试,只需转到命令行中的 NumPy 根目录并执行:
代码语言:javascript复制spin bench
这将构建 NumPy,并运行在 benchmarks/
中定义的所有可用基准测试。(注意:这可能需要一些时间。为了测量执行时间的分布,每个基准测试会运行多次。)
为了在本地测试基准,最好不带复制地运行这些:
代码语言:javascript复制cd benchmarks/
export REGEXP="bench.*Ufunc"
asv run --dry-run --show-stderr --python=same --quick -b $REGEXP
正则表达式用于匹配基准的存储在 $REGEXP
中,而 –quick 用于避免重复。
要从特定的基准模块,比如 bench_core.py
,运行基准测试,只需在文件名后面添加无扩展名的文件名即可:
spin bench -t bench_core
要运行在类中定义的基准,比如 bench_creation.py
中的 MeshGrid
:
spin bench -t bench_creation.MeshGrid
要将基准测试结果的变化与另一个版本/提交/分支进行比较,使用 --compare
选项(或等价的 -c
):
spin bench --compare v1.6.2 -t bench_core
spin bench --compare 20d03bcfd -t bench_core
spin bench -c main -t bench_core
上述所有命令都会在控制台中以纯文本形式显示结果,并且结果不会被保存以便与将来的提交进行比较。为了更好地控制,实现图形化视图,并且将结果保存以便将来比较,可以运行 ASV 命令(记录结果并生成 HTML):
代码语言:javascript复制cd benchmarks
asv run -n -e --python=same
asv publish
asv preview
更多关于如何使用 asv
的信息可以在ASV 文档中找到。像往常一样,可以通过 asv --help
和 asv run --help
获取命令行帮助。
版本基准测试
要在不同的本地机器上仅对发布进行基准测试或进行可视化,可以先生成带有其提交的标签,然后使用 asv
运行,即:
cd benchmarks
# Get commits for tags
# delete tag_commits.txt before re-runs
for gtag in $(git tag --list --sort taggerdate | grep "^v"); do
git log $gtag --oneline -n1 --decorate=no | awk '{print $1;}' >> tag_commits.txt
done
# Use the last 20
tail --lines=20 tag_commits.txt > 20_vers.txt
asv run HASHFILE:20_vers.txt
# Publish and view
asv publish
asv preview
有关贡献这些的详细信息,请参阅基准测试结果存储库。
编写基准测试
参见ASV 文档,了解如何编写基准的基本知识。
一些需要考虑的事项:
- 基准套件应该可以与任何 NumPy 版本一起使用。
- 基准参数等不应取决于安装了哪个 NumPy 版本。
- 尽量保持基准的运行时间合理。
- 最好使用 ASV 的
time_
方法来进行基准测试时间,而不是通过time.clock
自己测量时间,即使在编写基准时需要做一些调整。 - 通常,应该将数组等准备工作放在
setup
方法中而不是时间 _
方法中,以避免预备时间和基准操作的时间被计算在一起。 - 请注意,使用
np.empty
或np.zeros
创建的大型数组可能不会被分配到物理内存中,直到内存被访问。如果希望实现这种行为,请确保在设置函数中将其注释。如果正在进行算法基准测试,用户不太可能在新创建的空/零数组上执行该算法。可以通过在创建数组后调用np.ones
或arr.fill(value)
来强制发生页错误。
用法
除非另有说明,否则 Airspeed Velocity 会自行管理构建和 Python 虚拟环境。要运行基准测试,您无需将 NumPy 的开发版安装到当前的 Python 环境中。
在开始之前,请确保已安装 airspeed velocity。默认情况下,asv 支持 anaconda 和 virtualenv:
代码语言:javascript复制pip install asv
pip install virtualenv
在贡献新的基准测试之前,应在本地测试它们,然后再提交拉取请求。
要运行所有基准测试,转到命令行处的根 NumPy 目录并执行:
代码语言:javascript复制spin bench
这将构建 NumPy 并运行 benchmarks/
中定义的所有可用的基准测试。(注意:这可能需要一段时间。每个基准测试运行多次以测量执行时间的分布。)
对于测试基准测试,最好在没有重复情况下运行这些基准测试:
代码语言:javascript复制cd benchmarks/
export REGEXP="bench.*Ufunc"
asv run --dry-run --show-stderr --python=same --quick -b $REGEXP
正则表达式用于匹配基准测试的 $REGEXP
存储,并使用 –quick 避免重复。
要从特定的基准测试模块(如 bench_core.py
)运行基准测试,只需附加不带扩展名的文件名:
spin bench -t bench_core
要运行在类中定义的基准测试(如 bench_creation.py
中的 MeshGrid
):
spin bench -t bench_creation.MeshGrid
要将基准测试结果与另一个版本/提交/分支进行比较,请使用 --compare
选项(或等效的 -c
):
spin bench --compare v1.6.2 -t bench_core
spin bench --compare 20d03bcfd -t bench_core
spin bench -c main -t bench_core
上述所有命令在控制台以纯文本形式显示结果,并且结果不会保存以便与将来的提交进行比较。为了更好地控制和进行图形化查看,并且为将来的比较而保存结果,您可以运行 ASV 命令(记录结果并生成 HTML):
代码语言:javascript复制cd benchmarks
asv run -n -e --python=same
asv publish
asv preview
有关如何使用 asv
的更多信息,请参阅 ASV 文档。还可以通过 asv --help
和 asv run --help
来获取命令行帮助。
基准测试版本
若要在本地仅对不同计算机上的发布进行基准测试或可视化,可以先生成带有它们的提交的标签,然后再用 asv
运行:
cd benchmarks
# Get commits for tags
# delete tag_commits.txt before re-runs
for gtag in $(git tag --list --sort taggerdate | grep "^v"); do
git log $gtag --oneline -n1 --decorate=no | awk '{print $1;}' >> tag_commits.txt
done
# Use the last 20
tail --lines=20 tag_commits.txt > 20_vers.txt
asv run HASHFILE:20_vers.txt
# Publish and view
asv publish
asv preview
要了解有关如何进行贡献的详细信息,请参阅 benchmark results repository。
编写基准测试
有关如何编写基准测试的基础知识,请参阅 ASV 文档。
要考虑的一些事项:
- 基准测试套件应该可以与任何 NumPy 版本一起导入。
- 基准测试的参数等不应依赖于安装的 NumPy 版本。
- 尽量保持基准测试运行时间合理。
- 在进行基准测试时,首选 ASV 的
time_
方法来测量时间,而不是通过time.clock
进行测量,即使在编写基准测试时需要进行一些调整。 - 准备数组等操作通常应该放在
setup
方法中,而不是放在time_
方法中,以避免将准备时间与基准测试操作的时间计算在一起。 - 请注意,使用
np.empty
或np.zeros
创建的大型数组可能不会在物理内存中分配,直到内存被访问。如果希望出现这种行为,请确保在设置函数中进行注释。如果正在对算法进行基准测试,那么不太可能有用户在新创建的空/零数组上执行该算法。可以在设置阶段通过在创建数组后调用np.ones
或arr.fill(value)
来强制引发页面错误。
对于下游软件包的作者
原文:
numpy.org/doc/1.26/dev/depending_on_numpy.html
本文旨在解释编写依赖于 NumPy 的软件包的一些最佳实践。
了解 NumPy 的版本和 API/ABI 稳定性
NumPy 使用符合PEP 440规范的版本方案:major.minor.bugfix
。Major版本是非常不寻常的(NumPy 仍然是版本1.xx
),如果发生这种情况,可能表示 ABI 中断。Minor版本定期发布,通常每 6 个月发布一次。次要版本包含新功能、废弃项和以前废弃的代码的移除。Bugfix版本更频繁发布;它们不包含任何新功能或废弃项。
需要了解的重要信息是,NumPy 和 Python 本身以及大多数其他众所周知的科学 Python 项目不使用语义化版本。相反,向后不兼容的 API 更改需要至少两个版本的废弃警告。更多细节请参见NEP 23 — Backwards compatibility and deprecation policy。
NumPy 具有 Python API 和 C API。C API 可以直接使用或通过 Cython、f2py 或其他类似工具使用。如果你的软件包使用 C API,那么 NumPy 的 ABI(应用程序二进制接口)的稳定性就很重要。NumPy 的 ABI 是向前但不是向后兼容的。这意味着:针对某个给定版本的 NumPy 编译的二进制文件仍可以与更新的 NumPy 版本正确运行,但不能与旧版本一起运行。
针对 NumPy 的主分支或预发布版本进行测试
对于依赖于 NumPy 的大型且活跃维护的软件包,我们建议使用 CI 来对开发版本的 NumPy 进行测试。为了方便起见,每晚都会提供构建版本的 NumPy。可以在anaconda.org/scientific-python-nightly-wheels/
获取。示例安装命令:
pip install -U --pre --only-binary :all: -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy
这有助于检测在下一个 NumPy 发布之前需要修复的 NumPy 回归。此外,我们建议在 CI 中对此作业的警告中引发错误,无论是全部警告还是至少DeprecationWarning
和FutureWarning
。这会提前警告 NumPy 的更改,以便调整您的代码。
添加 NumPy 依赖项
构建时依赖项
注意
在 NumPy 1.25 之前,NumPy C-API 是不向后兼容的。这意味着当使用早于 1.25 的 NumPy 版本进行编译时,您必须使用您希望支持的最旧版本进行编译。可以使用oldest-supported-numpy来完成。请参阅NumPy 1.24 文档。
如果某个软件包直接使用 NumPy C API,或者使用依赖于它的其他工具(如 Cython 或 Pythran),那么 NumPy 就是该软件包的构建时依赖项。
默认情况下,NumPy 将暴露一个与最旧兼容 Python 版本支持的最旧 NumPy 版本向后兼容的 API。NumPy 1.25.0 支持 Python 3.9 及更高版本,NumPy 1.19 是第一个支持 Python 3.9 的版本。因此,我们保证在使用默认值时,NumPy 1.25 将暴露与 NumPy 1.19 兼容的 C-API(确切版本在 NumPy 内部头文件中设置)。
NumPy 也对所有次要版本具有向前兼容性,但是主要版本将需要重新编译。
默认行为可以通过添加以下内容进行自定义:
代码语言:javascript复制#define NPY_TARGET_VERSION NPY_1_22_API_VERSION
在每个需要 NumPy C-API 的扩展模块中(使用相应的-D
编译器标志)之前包含任何 NumPy 头文件。这主要在于,如果您需要使用新添加的 API,那么可能无法与旧版本兼容。
如果出于某种原因,您希望默认情况下编译为当前安装的 NumPy 版本,您可以添加:
代码语言:javascript复制#ifndef NPY_TARGET_VERSION
#define NPY_TARGET_VERSION NPY_API_VERSION
#endif
这允许用户通过-DNPY_TARGET_VERSION
覆盖默认值。此定义对于每个扩展模块(使用import_array()
)必须一致,并且也适用于 umath 模块。
当您针对 NumPy 进行编译时,您应该向pyproject.toml
添加适当的版本限制(请参阅 PEP 517)。由于您的扩展将不与新的 NumPy 主要版本兼容,并且可能与非常旧的版本不兼容,因此这是必需的。
对于 conda-forge 软件包,请参阅此处。
截至目前,通常只需包括:
代码语言:javascript复制host:
- numpy
run:
- {{ pin_compatible('numpy') }}
注意
到 NumPy 1.25 时,NumPy 2.0 预计将成为 NumPy 的下一个版本。预计 NumPy 2.0 发布将需要不同的固定版本,因为 NumPy 2 将需要以便与 NumPy 1.x 和 2.x 兼容。
运行时依赖和版本范围
NumPy 本身和许多核心科学 Python 软件包已经就放弃对旧 Python 和 NumPy 版本的支持达成一致:NEP 29 — 推荐 Python 和 NumPy 版本支持作为社区政策标准.我们建议所有依赖于 NumPy 的软件包遵循 NEP 29 中的建议。
对于运行时依赖项,请在setup.py
中使用install_requires
指定版本范围(假设您使用numpy.distutils
或setuptools
进行构建)。
大多数依赖于 NumPy 的库不需要设置上限版本范围:NumPy 会小心保持向后兼容性。
如果你(a)是一个保证频繁发布的项目,(b)使用了大量 NumPy 的 API 功能,以及(c)担心 NumPy 的变化可能会破坏你的代码,你可以设置一个上限<MAJOR.MINOR N
,其中 N 不少于 3,MAJOR.MINOR
是 NumPy 的当前发布版本 [*] 。如果你使用 NumPy C API(直接或通过 Cython),你还可以固定当前主要版本,以防止 ABI(应用程序二进制接口)破坏。请注意,设置 NumPy 的上限可能会影响库与其他更新包一起安装的能力。
注意
SciPy 有更多关于如何构建轮子以及处理构建时和运行时依赖关系的文档这里。
NumPy 和 SciPy 的轮子构建 CI 也可能作为参考,可以在这里找到 NumPy 的,以及这里找到 SciPy 的。
了解 NumPy 的版本控制和 API/ABI 稳定性
NumPy 使用标准的,PEP 440兼容的版本控制方案:major.minor.bugfix
。重大发布是非常不寻常的(NumPy 目前仍然是版本1.xx
),如果发生,很可能表示 ABI 破坏。次要版本定期发布,通常每 6 个月一次。次要版本包含新功能、弃用功能,以及移除之前弃用的代码。Bugfix发布更频繁;它们不包含任何新功能或弃用。
值得注意的是,NumPy,以及 Python 本身和大多数其他知名的科学 Python 项目,不使用语义版本控制。相反,不兼容的 API 更改需要至少在两个发布版本中提供弃用警告。更多详情,请参见NEP 23 — 向后兼容性和废弃策略。
NumPy 有 Python API 和 C API。C API 可以直接使用,也可以通过 Cython、f2py 或其他类似工具使用。如果你的包使用 C API,那么 NumPy 的 ABI(应用程序二进制接口)稳定性非常重要。NumPy 的 ABI 是向前而不向后兼容的。这意味着:针对特定 NumPy 版本编译的二进制文件将会在新的 NumPy 版本中正确运行,但不会在旧版本中正确运行。
对 NumPy 主分支或预发行版进行测试
对于依赖 NumPy 的大型、积极维护的包,我们建议在 CI 中对 NumPy 的开发版本进行测试。为了方便起见,夜间构建作为轮子提供在anaconda.org/scientific-python-nightly-wheels/
。示例安装命令:
pip install -U --pre --only-binary :all: -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple numpy
这有助于检测需要在下一个 NumPy 发布之前进行修复的 NumPy 中的回归。此外,我们建议在 CI 中对此作业中的警告引发错误,包括所有警告或至少 DeprecationWarning
和 FutureWarning
。这样可以及早警示您需要调整代码以适应 NumPy 中的更改。
添加对 NumPy 的依赖
构建时依赖
注意
在 NumPy 1.25 之前,NumPy C-API 不 向后兼容。这意味着,在使用早于 1.25 的 NumPy 版本进行编译时,您必须使用您希望支持的最旧版本。可以通过使用 oldest-supported-numpy 来完成。请参阅 NumPy 1.24 文档。
如果包直接使用 NumPy C API,或者使用一些其他依赖于它的工具,比如 Cython 或 Pythran,那么 NumPy 就是包的 构建时 依赖关系。
默认情况下,NumPy 将公开一个与最旧的兼容 Python 版本支持的最旧 NumPy 版本向后兼容的 API。NumPy 1.25.0 支持 Python 3.9 及更高版本,而 NumPy 1.19 是第一个支持 Python 3.9 的版本。因此,我们保证在使用默认设置时,NumPy 1.25 将公开与 NumPy 1.19 兼容的 C-API(确切版本设置在 NumPy 内部头文件中)。
NumPy 也对所有次要发布版向前兼容,但主要发布版将需要重新编译。
默认行为可以通过例如添加来定制:
代码语言:javascript复制#define NPY_TARGET_VERSION NPY_1_22_API_VERSION
在任何需要 NumPy C-API 的扩展模块中,包括任何 NumPy 头文件(或等效的 -D
编译器标志)。这主要是有用的,如果您需要使用新增的 API,但同时无法与旧版本兼容。
如果出于某种原因,默认情况下希望以当前安装的 NumPy 版本进行编译,可以添加:
代码语言:javascript复制#ifndef NPY_TARGET_VERSION
#define NPY_TARGET_VERSION NPY_API_VERSION
#endif
这允许用户通过 -DNPY_TARGET_VERSION
来覆盖默认设置。该定义对于每个扩展模块(使用 import_array()
)必须是一致的,并且也适用于 umath 模块。
当您针对 NumPy 进行编译时,应该向您的 pyproject.toml
(参见 PEP 517)添加适当的版本限制。由于您的扩展可能与新的 NumPy 主要版本不兼容,并且可能与非常旧的版本也不兼容。
对于 conda-forge 包,请参见 此处。
截至目前,通常情况下只需包含:
代码语言:javascript复制host:
- numpy
run:
- {{ pin_compatible('numpy') }}
注意
在 NumPy 1.25 时,NumPy 2.0 预计是下一个 NumPy 发布版本。预计 NumPy 2.0 发布将需要不同的固定,因为 NumPy 2 将需要兼容 NumPy 1.x 和 2.x。
运行时依赖 & 版本范围
NumPy 本身和许多核心科学 Python 包都已经同意了一个关于放弃支持旧 Python 和 NumPy 版本的时间表:NEP 29 — 推荐 Python 和 NumPy 版本支持作为社区政策标准。我们建议所有依赖 NumPy 的软件包遵循 NEP 29 的建议。
对于运行时依赖,使用setup.py
中的install_requires
来指定版本范围(假设您使用numpy.distutils
或setuptools
来构建)。
大多数依赖于 NumPy 的库不需要设置一个上限版本:NumPy 会小心地保留向后兼容性。
也就是说,如果您是(a)一个保证频繁发布的项目,(b)使用了 NumPy API 的大部分功能,和(c)担心 NumPy 的变化可能会破坏您的代码,您可以设置<主要.次要 N
的上限界限,N 不小于 3,并且主要.次要
是当前 NumPy 版本[*]。如果您使用 NumPy C API(直接或通过 Cython),您也可以固定当前主要版本以防止 ABI 破坏。请注意,设置 NumPy 的上限可能会影响您的库与其他更新的软件包一起安装的能力。
注意
SciPy 有更多关于如何构建 wheel 并处理其构建时和运行时依赖关系的文档在这里。
NumPy 和 SciPy 的 wheel 构建 CI 也可能是一个很好的参考,可以在这里找到 NumPy 的,在这里找到 SciPy 的。
构建时的依赖
注意
在 NumPy 1.25 之前,NumPy C-API 是不向后兼容的。这意味着在使用早于 1.25 的 NumPy 版本进行编译时,您必须用您希望支持的最老版本进行编译。这可以通过使用oldest-supported-numpy来实现。请参阅NumPy 1.24 文档。
如果一个软件包直接使用 NumPy C API,或者使用其他依赖于它的工具,如 Cython 或 Pythran,NumPy 就是软件包的构建时依赖。
默认情况下,NumPy 将暴露一个与支持当前最老的 Python 版本的最老的兼容 NumPy 版本兼容的 API。NumPy 1.25.0 支持 Python 3.9 及更高版本,而 NumPy 1.19 是第一个支持 Python 3.9 的版本。因此,我们保证,当使用默认设置时,NumPy 1.25 将暴露一个与 NumPy 1.19 兼容的 C-API(确切的版本在 NumPy 内部头文件中设置)。
NumPy 对于所有次要版本都是向前兼容的,但一个主要版本将需要重新编译。
默认行为可以通过添加以下内容来自定义,例如:
代码语言:javascript复制#define NPY_TARGET_VERSION NPY_1_22_API_VERSION
在每个需要 NumPy C-API 的扩展模块中(或使用等效的-D
编译器标志)之前包含任何 NumPy 头文件。如果你需要使用新添加的 API,这主要是有用的,尽管代价是不兼容旧版本。
如果出于某种原因你希望默认编译为当前安装的 NumPy 版本,你可以添加:
代码语言:javascript复制#ifndef NPY_TARGET_VERSION
#define NPY_TARGET_VERSION NPY_API_VERSION
#endif
这允许用户通过-DNPY_TARGET_VERSION
来覆盖默认值。每个扩展模块(使用import_array()
)必须保持一致,并且也适用于 umath 模块。
当你编译针对 NumPy 时,应该在pyproject.toml
中添加适当的版本限制(参见 PEP 517)。因为你的扩展将不兼容新的 NumPy 主要发布,并且可能不兼容非常旧的版本。
对于 conda-forge 包,请查看这里。
目前来说,通常只需包含以下内容即可:
代码语言:javascript复制host:
- numpy
run:
- {{ pin_compatible('numpy') }}
注意
截至 NumPy 1.25,NumPy 2.0 有望是下一个 NumPy 版本。NumPy 2.0 发布预计需要不同的固定,因为需要 NumPy 2 才能兼容 NumPy 1.x 和 2.x。
运行时依赖和版本范围
NumPy 本身和许多核心科学 Python 包已经就放弃支持旧的 Python 和 NumPy 版本的时间表达成一致:NEP 29 — 推荐 Python 和 NumPy 版本支持作为社区政策标准。我们建议所有依赖于 NumPy 的包遵循 NEP 29 中的建议。
对于运行时依赖,请在setup.py
中使用install_requires
指定版本范围(假设你使用numpy.distutils
或setuptools
进行构建)。
大多数依赖 NumPy 的库不需要设置上限版本:NumPy 会谨慎保留向后兼容性。
也就是说,如果你(a)是一个保证频繁发布的项目,(b)使用了 NumPy 的大部分 API,(c)担心 NumPy 的更改可能会破坏你的代码,你可以将上限设置为 <MAJOR.MINOR N
,其中 N 不少于 3,并且MAJOR.MINOR
是当前 NumPy 版本 [*]。如果你使用 NumPy C API(直接使用或通过 Cython),你也可以固定当前主要版本以防止 ABI 破坏。请注意,设置 NumPy 的上限可能会影响你的库与其他更新的包能否同时安装。
注意
SciPy 有更多关于如何构建 wheel 和处理构建时和运行时依赖的文档,请查看这里。
NumPy 和 SciPy 的 wheel 构建 CI 也可能有用作为参考,可以在这里找到 NumPy和这里找到 SciPy。
发布一个版本
原文:
numpy.org/doc/1.26/dev/releasing.html
以下指南详细介绍了如何准备 NumPy 的发布。
如何准备发布
这些说明提供了构建 NumPy 二进制发布版本所需的概述。
当前的构建和发布信息
有关以下位置可以找到有用的信息:
- 源代码
- INSTALL.rst
- pavement.py
- NumPy 文档
-
github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst
-
github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst
-
github.com/numpy/numpy/blob/main/doc/BRANCH_WALKTHROUGH.rst
-
- 发行脚本
github.com/numpy/numpy-vendor
支持的平台和版本
NEP 29概述了支持的 Python 版本;2020 年上半年,支持 Python >= 3.6. 我们每次合并代码到主分支时都会对所有这些版本进行测试。部分版本可能提供了二进制安装包(详见下文)。
- OS X 支持的 OS X 版本 >= 10.9 ,有关 Python 版本的支持情况请参见 NEP 29。我们为与 Python.org Python、系统提供的 Python、homebrew 和 macports 兼容的 OS X 上构建了二进制 wheel 文件 —— 参见此 OSX wheel 构建摘要 以获取详细信息。
- Windows 我们在 Windows 上构建 32 位和 64 位的 wheel 文件。支持 Windows 7, 8 和 10 。我们使用 mingw-w64 工具链、cibuildwheels 和 GitHub actions 来构建 NumPy。
- Linux 我们为 NumPy 构建和发布了 manylinux2014 的 wheel 文件。许多 Linux 发行版包括了他们自己构建的二进制 NumPy 版本。
- BSD / Solaris 没有提供二进制文件,但已经有关于 Solaris 和 BSD 的成功构建报告。
工具链
我们在云基础设施上构建所有的 wheel 文件 —— 因此这份编译器列表仅供本地构建的信息和调试参考。详见numpy wheels存储库中的 .travis.yml
脚本,其中含有已过时的创建构建脚本的来源,使用 multibuild 工具。
编译器
在每个平台上,使用与 Python 本身构建时相同的 gcc 版本。目前如下:
- OS X 构建目前在 travis 上使用 clang。当针对 Python.org 安装包构建时,似乎可以安全地从 travis-ci 的 OS X 10.9 虚拟机上构建适用于 OSX >= 10.6 的二进制 wheel;
- Windows 构建使用 mingw-w64 工具链;
- Manylinux2014 wheels 使用 Manylinux docker 镜像提供的 gcc。
您将需要 Cython 来构建二进制文件。Cython 将 NumPy 分发中的 .pyx
文件编译为 .c
文件。
OpenBLAS
所有的 wheels 链接到通过 openblas-libs 仓库提供的 OpenBLAS 版本。共享对象(或 DLL)与 wheel 一起发布,重命名以防止与文件系统中可能存在的其他 OpenBLAS 共享对象的名称冲突。
构建源代码存档和 wheels
NumPy wheels 和 sdist 现在使用 cibuildwheel 和 github actions 构建。
构建文档
我们不再构建 pdf 文件,只有 html 文档。需要上传到文档服务器的 numpy-html.zip
可以使用 spin docs dist
构建。
要将必要的文档构建依赖项安装到开发环境中,请运行 pip install -r doc_requirements.txt
。
上传到 PyPI
上传所需的唯一应用程序是
- twine (pip)。
您还需要一个 PyPI 令牌,最好将其保存在一个钥匙链上。请参阅 twine 的 keyring 文档以了解如何做到这一点。
生成作者和 PR 列表
您将需要个人访问令牌 help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
,以便脚本可以访问 github NumPy 仓库。
- gitpython(pip)
- pygithub(pip)
发布的内容
- Wheels 我们目前支持 Windows、OSX 和 Linux 上的 Python 3.8-3.10。
- Windows:32 位和 64 位的 wheels 使用 Github actions 构建;
- OSX:使用 Github actions 构建的 x64_86 和 arm64 OSX wheels;
- Linux:使用 Github actions 构建的 x64_86 和 aarch64 Manylinux2014 wheels。
- 其他 发布说明和变更日志
- 源代码分发 我们以 .tar.gz 格式构建源代码发布版。
发布流程
确定发布计划
一个典型的发布计划是一个 beta 版本、两个发布候选版本和一个最终版本。最好先在邮件列表上讨论时间,以便人们及时提交他们的代码、合并文档 wiki 编辑等。确定日期后,在主分支上创建一个新的 maintenance/x.y.z 分支,并为下一个版本添加新的空白发布说明,并更新 Trac 里程碑。
确保当前分支正确构建一个软件包
当 PR 标题以 REL
开头时,CI 构建 wheels。在发布之前,您最后的 PR 应该标记为这样,并且所有测试都应该通过。您也可以执行以下操作:
git clean -fxdq
python setup.py bdist_wheel
python setup.py sdist
有关构建过程的详细信息,最好阅读下面的逐步说明。
注意
以下步骤将针对 beta 版、发布候选版和最终发布版进行重复。
检查弃用项
在制作发布分支之前,应检查所有应该删除的弃用代码是否实际删除,所有新的弃用说明都应在文档字符串或弃用警告中说明代码将在哪个版本被移除。
检查 C API 版本号
C API 版本需要在三个地方跟踪
- numpy/core/setup_common.py
- numpy/core/code_generators/cversions.txt
- numpy/core/include/numpy/numpyconfig.h
这个过程有三个步骤。
- 如果 API 发生了变化,请在 setup_common.py 中增加 C_API_VERSION。仅当针对当前 API 编译的任何代码与上一个已发布的 NumPy 版本向后兼容时,API 才未改变。对 C 结构的任何更改或对公共接口的添加将使新 API 不向后兼容。
- 如果步骤 1 中的 C_API_VERSION 已更改,或者 API 的哈希值已更改,需要更新 cversions.txt 文件。要检查哈希值,请运行脚本 numpy/core/cversions.py,并注意打印的 API 哈希值。如果该哈希值与 numpy/core/code_generators/cversions.txt 中的最后一个哈希值不匹配,那么哈希值已更改。使用相应的 C_API_VERSION 和哈希值,在 cversions.txt 中添加新条目。如果 API 版本没有更改,但哈希值不同,则需要注释掉该 API 版本的先前条目。例如,在 NumPy 1.9 中添加了注释,这改变了哈希值,但 API 与 1.8 中的相同。哈希值用作 API 变更的检查,但并非是最终确定其是否变更的依据。 如果步骤 1 和 2 执行正确,编译发布不应该出现“在构建开始时检测到 API 不匹配”的警告。
- numpy/core/include/numpy/numpyconfig.h 将需要一个新的 NPY_X_Y_API_VERSION 宏,其中 X 和 Y 是版本的主要和次要版本号。只有当包含文件中的一些函数或宏被弃用时,才需要增加给该宏的值,从上一版本增加即可。
numpy/core/setup_common.py 中的 C ABI 版本号仅适用于主要版本的更新。
检查发布说明
使用towncrier构建发布说明并提交更改。这将从doc/release/upcoming_changes
中删除所有片段,并添加doc/release/<version>-note.rst
。
towncrier build –version “” git commit -m”Create release note”
检查发布说明是否最新。
使用 Highlight 部分更新发布说明。提及以下一些内容:
- 主要新功能
- 弃用和删除的功能
- 支持的 Python 版本
- 对于 SciPy,支持的 NumPy 版本
- 不久的将来展望
逐步指引
这是对在 Linux 上进行的 NumPy 1.21.0 发布的演练,修改为使用 GitHub Actions 和 cibuildwheels 构建,并上传到NumPy 的 anaconda.org 暂存库。命令可以复制到命令行中,但一定要将 1.21.0 替换为正确的版本。应与通用发布指南一起阅读。
设施准备
在开始发布之前,请使用 *_requirements.txt
文件确保您拥有所需的软件。大多数软件都可以使用 pip 安装,但某些软件将需要 apt-get、dnf 或您的系统用于软件的任何其他方式。您还需要一个 GitHub 个人访问令牌(PAT)来推送文档。有几种方法可以简化流程:
- Git 可以设置使用密钥环来存储您的 GitHub 个人访问令牌。在线搜索详细信息。
- 您可以使用
keyring
应用程序存储 twine 的 PyPI 密码。查看在线 twine 文档以获取详细信息。
发布准备
添加/删除 Python 版本
当添加或删除 Python 版本时,需要编辑三个文件:
- .github/workflows/wheels.yml # 用于 github cibuildwheel
- .travis.yml # 用于 cibuildwheel aarch64 构建
- setup.py # 用于分类器和最低版本检查。
在主分支上进行这些更改,并在必要时进行回溯。在提交摘要中使用 BLD: 前缀(构建标签)将导致运行轮子构建,以便对更改进行测试。我们目前在第一个 Python rc 之后的多个 Linux 平台和 cibuildwheel 支持的 Python 版本中发布轮子。对于 Python 3.11,我们能够在 rc1 公告发布后的一周内发布。
回溯拉取请求
标记为此发布的更改必须回溯到维护/1.21.x 分支。
更新发布文档
在发布之前通常需要更新或创建四个文档:
- 变更日志
- 发布说明
-
.mailmap
文件 - 文件
doc/source/release.rst
这些更改应作为针对维护分支的普通 PR 进行。发布后,除了 doc/source/release.rst
外,所有文件都需要向主分支进行向前移植。
生成变更日志
变更日志是使用变更日志工具生成的:
代码语言:javascript复制$ python tools/changelog.py $GITHUB v1.20.0..maintenance/1.21.x > doc/changelog/1.21.0-changelog.rst
其中 GITHUB
包含您的 GitHub 访问令牌。文本需要检查非标准贡献者名称,并删除 dependabot 条目。还要删除可能存在于 PR 标题中的任何链接,因为它们在 markdown 中不易转换,用等宽文本替换它们。非标准的贡献者名称应通过更新 .mailmap
文件来修复,这是一项艰巨的工作。最好在达到此点之前进行几次试运行,并使用 GitHub 问题对恶意用户发出提醒,以获取所需信息。
完成发布说明
如果这是系列中的第一个发布,则将生成发布说明,查看doc/release/upcoming_changes/README.rst
中的发布说明以查看如何操作。生成发布说明还会删除doc/release/upcoming_changes/
中的所有新闻片段文件。
生成的发布说明总是需要一些修复,引言需要编写,重要的更改应该被指出。对于补丁发布,可能还会追加更改日志文本,但对于初始版本不会,因为它太长。查看以前的发布说明以了解如何操作。请注意,如果存在顶部的:orphan:
标记,需要更改为.. currentmodule:: numpy
,并且需要更新doc/source/release.rst
索引文件。
检查pavement.py
文件
检查pavement.py
文件指向正确的发布说明。应该在上次发布后进行更新,但如果没有,请现在进行修复:
$ gvim pavement.py
发布演示
请注意,在下面的代码段中,upstream
指 GitHub 上的根存储库,origin
指其在您个人 GitHub 存储库中的派生。如果您没有派生存储库,而是在本地克隆了它,则可能需要进行调整。您还可以编辑.git/config
并添加upstream
(如果尚未存在)。
1. 准备发布提交
检查用于发布的分支,确保它是最新的,并清理存储库:
代码语言:javascript复制$ git checkout maintenance/1.21.x
$ git pull upstream maintenance/1.21.x
$ git submodule update
$ git clean -xdfq
理智检查:
代码语言:javascript复制$ python3 -m spin test -m full
标记发布并推送标签。这需要对 numpy 存储库有写权限:
代码语言:javascript复制$ git tag -a -s v1.21.0 -m"NumPy 1.21.0 release"
$ git push upstream v1.21.0
如果需要由于错误删除标签:
代码语言:javascript复制$ git tag -d v1.21.0
$ git push --delete upstream v1.21.0
2. 构建轮子
通过 cibuildwheel 生成轮子(首选)
在此过程开始时标记构建将通过 cibuildwheel 触发轮子生成,并将轮子和 sdist 上传到暂存存储库。在 GitHub 操作中运行(对于所有基于 x86 和 macOS arm64 的轮子)大约需要 1 小时 15 分钟。在 travis 上运行(对于 aarch64)需要更少的时间。您可以在暂存存储库上查看已上传的文件,但请注意它与您所看到的运行作业并不完全同步。
如果希望手动触发轮子生成,可以这样做:
- 在 GitHub 操作-> Wheel builder上有“运行工作流”按钮,点击它并选择要构建的标签
- 在travis上有一个“更多选项”按钮,点击它并选择要构建的分支。看起来没有构建标签的选项。
如果轮子生成失败是由于不相关的原因,你可以单独重新运行:
- 在 GitHub 操作中选择Wheel builder,点击包含您想要重新运行的构建的提交。左侧有轮子生成的列表,选择您想要重新运行的那个,然后在生成的页面上点击逆时针箭头按钮。
- 在travis上选择失败的构建,这将带您到该构建的 travis 作业。点击重新启动作业按钮。
请注意,如果您需要重新运行作业,则需要删除 anaconda staging repository中已上传的文件(如果有的话)。旧文件将不会被覆盖。
3. 下载轮子
当所有轮子都已成功构建和分阶段时,使用tools/download-wheels.py
脚本从 Anaconda 分阶段目录下载它们:
$ cd ../numpy
$ mkdir -p release/installers
$ python3 tools/download-wheels.py 1.21.0
4. 生成 README 文件
这需要在所有安装程序被下载后完成,但在更新路面文件以进行持续开发之前完成:
代码语言:javascript复制$ paver write_release
5. 将维护分支重置为开发状态(跳过预发布)
创建下一个版本的发布说明并编辑它们以设置版本。这些说明将是一个框架,内容很少:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.21.1-notes.rst
$ gvim doc/source/release/1.21.1-notes.rst
$ git add doc/source/release/1.21.1-notes.rst
将新的发布说明添加到文档发布列表中,并在pavement.py
中更新RELEASE_NOTES
变量:
$ gvim doc/source/release.rst pavement.py
提交结果:
代码语言:javascript复制$ git commit -a -m"REL: prepare 1.21.x for further development"
$ git push upstream HEAD
6. 上传到 PyPI
使用twine
上传到 PyPI。最近的twine
版本是在最近的 PyPI 更改后需要的,这里使用的版本是3.4.1
:
$ cd ../numpy
$ twine upload release/installers/*.whl
$ twine upload release/installers/numpy-1.21.0.tar.gz # Upload last.
如果其中一个命令在中间中断,您可能需要选择性地上传剩余的文件,因为 PyPI 不允许相同的文件上传两次。应该最后上传源文件,以避免在此过程中 pip 用户访问文件时可能出现的同步问题,这会导致 pip 从源代码构建而不是下载二进制 wheel。PyPI 只允许单个源分发,这里我们选择了 zip 归档。
7. 将文件上传到 github
转到github.com/numpy/numpy/releases
,那里应该有一个v1.21.0 tag
,点击它并点击该标签的编辑按钮。有两种添加文件的方法,使用可编辑的文本窗口和作为二进制上传。首先编辑release/README.md
,该文件是使用 pandoc 从 rst 版本翻译的。需要修复的内容:如果包括,来自 changelog 的 PR 行被包裹并需要解包,链接应更改为等宽文本。然后将内容复制到剪贴板并粘贴到文本窗口中。可能需要多次尝试才能看起来正确。然后
- 将
release/installers/numpy-1.21.0.tar.gz
上传为二进制文件。 - 将
release/README.rst
上传为二进制文件。 - 将
doc/changelog/1.21.0-changelog.rst
上传为二进制文件。 - 如果这是预发布,请勾选预发布按钮。
- 在底部点击
{发布,更新}发布
按钮。
8. 将文档上传到 numpy.org(跳过预发布)
注意
您将需要一个 GitHub 个人访问令牌来推送更新。
这一步仅适用于最终版本,对于预发布和大多数补丁发布,可以跳过。make merge-doc
将numpy/doc
仓库克隆到doc/build/merge
并用新文档更新它:
$ git clean -xdfq
$ git co v1.21.0
$ pushd doc
$ make docenv && source docenv/bin/activate
$ make merge-doc
$ pushd build/merge
如果发布系列是一个新的,你需要在doc/build/merge/index.html
首页的“在这里插入”注释后添加一个新部分:
$ gvim index.html /'insert here'
此外,更新版本切换器 json 文件以添加新版本,并更新标记为*(stable)*的版本:
代码语言:javascript复制$ gvim _static/versions.json
否则,只需要更新zip
链接的标签名称。因为我们不再生成pdf
文件,如果有的话,去掉pdf
文件的那行:
$ gvim index.html /'tag v1.21'
你可以在浏览器中“测试运行”新的文档,以确保链接有效:
代码语言:javascript复制$ firefox index.html # or google-chrome, etc.
更新稳定链接并更新:
代码语言:javascript复制$ ln -sfn 1.21 stable
$ ls -l # check the link
一切似乎令人满意后,更新、提交并上传更改:
代码语言:javascript复制$ python3 update.py
$ git commit -a -m"Add documentation for v1.21.0"
$ git push
$ deactivate
$ popd
$ popd
9. 在 numpy.org 上宣布发布(预发布除外)
假设你已经 forked github.com/numpy/numpy.org
:
$ cd ../numpy.org
$ git checkout main
$ git pull upstream main
$ git checkout -b announce-numpy-1.21.0
$ gvim content/en/news.md
- 对于所有的发布,转到页面底部添加一行链接。查看以前的链接作为示例。
- 对于循环中的
*.0
发布,在顶部添加一个新部分,简要描述新功能,并将新闻链接指向它。
提交并推送:
代码语言:javascript复制$ git commit -a -m"announce the NumPy 1.21.0 release"
$ git push origin HEAD
转到你的 Github fork 并创建一个 pull request。
10. 在邮件列表上宣布
应该在 numpy-discussion、scipy-devel、scipy-user 和 python-announce-list 邮件列表上宣布发布。查看以前的公告以获取基本模板。贡献者和 PR 名单与上面生成的发布说明相同。如果交叉发布,请确保 python-announce-list 是密件抄送,以便回复不会发送到该列表。
11. 发布后任务(预发布除外)
检出主分支并将文档更改前向加入:
代码语言:javascript复制$ git checkout -b post-1.21.0-release-update
$ git checkout maintenance/1.21.x doc/source/release/1.21.0-notes.rst
$ git checkout maintenance/1.21.x doc/changelog/1.21.0-changelog.rst
$ git checkout maintenance/1.21.x .mailmap # only if updated for release.
$ gvim doc/source/release.rst # Add link to new notes
$ git status # check status before commit
$ git commit -a -m"MAINT: Update main after 1.21.0 release."
$ git push origin HEAD
前往 GitHub 提交 PR。
12. 更新 oldest-supported-numpy
如果这个版本是第一个支持新的 Python 版本,或者第一个为新平台或 PyPy 版本提供轮子的版本,应该更新github.com/scipy/oldest-supported-numpy
中的版本固定。要么提交一个带有setup.cfg
更改的 PR,要么提交一个带有所需更改信息的问题。
分支演练
本指南包含了在 Linux 上分支 NumPy 1.21.x 的操作步骤。命令可以复制到命令行,但请务必根据实际版本替换 1.21 和 1.22。在制作分支之前,尽可能使.mailmap
尽可能新是个好习惯,可能需要几周的时间。
这应该与通用发布指南一起阅读。
分支
创建分支
这只需要在开始一个新的维护分支时才需要。由于 NumPy 现在依赖标签来确定版本,在主分支中开始新的开发周期需要一个有注释的标签。操作如下:
代码语言:javascript复制$ git checkout main
$ git pull upstream main
$ git commit --allow-empty -m'REL: Begin NumPy 1.22.0 development'
$ git push upstream HEAD
如果推送失败,因为新的 PR 已经合并,执行如下操作:
代码语言:javascript复制$ git pull --rebase upstream
并且重复推送。一旦推送成功,请打标签:
代码语言:javascript复制$ git tag -a -s v1.22.0.dev0 -m'Begin NumPy 1.22.0 development'
$ git push upstream v1.22.0.dev0
然后创建新的分支并推送:
代码语言:javascript复制$ git branch maintenance/1.21.x HEAD^
$ git push upstream maintenance/1.21.x
准备主分支进行进一步开发
创建 PR 分支以准备主分支进行进一步开发:
代码语言:javascript复制$ git checkout -b 'prepare-main-for-1.22.0-development' v1.22.0.dev0
删除发布说明碎片:
代码语言:javascript复制$ git rm doc/release/upcoming_changes/[0-9]*.*.rst
创建新的发行说明骨架并添加到索引中:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release/1.22.0-notes.rst # put the correct version
$ git add doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release.rst # add new notes to notes index
$ git add doc/source/release.rst
更新pavement.py
并更新RELEASE_NOTES
变量以指向新的说明:
$ gvim pavement.py
$ git add pavement.py
更新cversions.txt
以添加当前发行版。在这个早期阶段,不需要担心新的哈希值,只需在之前的做法后面添加注释即可:
$ gvim numpy/core/code_generators/cversions.txt
$ git add numpy/core/code_generators/cversions.txt
检查你的工作,提交并推送:
代码语言:javascript复制$ git status # check work
$ git commit -m'REL: Prepare main for NumPy 1.22.0 development'
$ git push origin HEAD
现在创建一个拉取请求。## 如何准备一个发行版
这些说明概述了构建 NumPy 二进制版本所需的必要步骤。
当前的构建和发��信息
有关有用的信息,请参见以下位置:
- 源代码树
- INSTALL.rst
- pavement.py
- NumPy 文档
-
github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst
-
github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst
-
github.com/numpy/numpy/blob/main/doc/BRANCH_WALKTHROUGH.rst
-
- 发行脚本
github.com/numpy/numpy-vendor
支持的平台和版本
NEP 29概述了支持的 Python 版本;在 2020 年上半年,这将是 Python >= 3.6. 我们每次将代码合并到主代码库时,都会对所有这些版本的 NumPy 进行测试。二进制安装程序可能仅适用于其中一部分版本(请见下文)。
- OS X 支持的 OS X 版本为 10.9 及以上,有关 Python 版本支持,请参见NEP 29(在 NumPy Enhancement Proposals 中)。我们构建了与 Python.org Python、系统 Python、homebrew 和 macports 兼容的 OSX 二进制 wheel 文件-有关详细信息,请参见此OSX wheel 构建摘要。
- Windows 我们在 Windows 上构建了 32 位和 64 位的 wheel 文件。支持 Windows 7、8 和 10。我们使用mingw-w64 工具链,cibuildwheels和 GitHub actions 来构建 NumPy。
- Linux 对于 NumPy,我们构建并发布了manylinux2014的 wheel 文件。许多 Linux 发行版中已经包含了自己的 NumPy 二进制版本。
- BSD / Solaris 不提供二进制文件,但已经有反馈表示在 Solaris 和 BSD 上成功构建。
工具链
我们在云计算环境中构建所有的 wheel 文件,所以这个编译器列表仅供信息和本地构建调试使用。使用 multibuild 可以在numpy wheels 存储库的.travis.yml
脚本中找到过时的构建脚本。
编译器
在各个平台上,使用的 gcc 版本与 Python 本身使用的版本相同。目前情况如下:
- 目前 travis 上的 OS X 构建使用clang。当针对 Python.org 安装程序构建时,似乎可以安全地从 travis-ci OSX 10.9 虚拟机构建 OSX >= 10.6 的二进制 wheels;
- Windows 构建使用mingw-w64 工具链;
- Manylinux2014 wheels 使用 Manylinux docker 镜像上提供的 gcc。
你需要 Cython 来构建二进制文件。Cython 将 NumPy 分发中的.pyx
文件编译成.c
文件。
OpenBLAS
所有的 wheels 链接到通过openblas-libs仓库提供的OpenBLAS的一个版本。共享对象(或 DLL)与 wheels 一起发布,重命名以防止与文件系统中可能存在的其他 OpenBLAS 共享对象发生重名冲突。
构建源代码存档和 wheels
NumPy 的 wheels 和 sdist 现在使用 cibuildwheel 与 github actions 构建。
生成文档
我们不再构建 pdf 文件,只有 html 文档。上传到文档服务器所需的numpy-html.zip
可以使用spin docs dist
构建。
要在您的开发环境中安装必要的文档构建依赖项,请运行pip install -r doc_requirements.txt
。
上传到 PyPI
上传所需的唯一应用程序是
- twine(pip)。
你还需要一个 PyPI 令牌,最好放在钥匙链上。请参阅 twine keyring文档,了解如何操作。
生成作者/PR 列表
你需要一个help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
,以便脚本可以访问 github 的 NumPy 仓库。
- gitpython(pip)
- pygithub(pip)
发布了什么
- Wheels 我们目前支持 Windows、OSX 和 Linux 上的 Python 3.8-3.10。
- Windows:32 位和 64 位 wheels 使用 Github actions 构建;
- OSX:x64_86 和 arm64 OSX wheels 使用 Github actions 构建;
- Linux:x64_86 和 aarch64 Manylinux2014 wheels 使用 Github actions 构建。
- 其他 发布说明和更新日志
- 源代码发布 我们以.tar.gz 格式构建源发布。
发布流程
确定发布计划
典型的发布计划是一个 beta 版、两个候选版本和一个最终版。最好先在邮件列表上讨论时间,以便人们能及时提交他们的提交,合并文档 wiki 编辑等。在确定日期后,创建一个新的 maintenance/x.y.z 分支,在主分支中添加新的空发布说明版本,并更新 Trac Milestones。
确保当前分支正确构建一个包
当 PR 标题以REL
开头时,CI 会构建 wheels。在发布之前,你的最后一个 PR 应该这样标记,并且所有的测试都应该通过。你也可以:
git clean -fxdq
python setup.py bdist_wheel
python setup.py sdist
关于构建过程的详细信息,最好阅读下面的逐步指南。
注意
以下步骤会重复进行 beta 版本,候选发布版本和最终发布版本。
检查废弃
在制作发布分支之前,应检查所有应移除的已废弃代码是否实际上已移除,并且所有新的弃用会在文档字符串或弃用警告中说明代码将在哪个版本中移除。
检查 C API 版本号
C API 版本需要在三个地方跟踪
- numpy/core/setup_common.py
- numpy/core/code_generators/cversions.txt
- numpy/core/include/numpy/numpyconfig.h
该过程有三个步骤。
- 如果 API 已更改,请在 setup_common.py 中递增 C_API_VERSION。只有在与上一个发布的 NumPy 版本具有向后兼容性的任何代码编译后,API 才不会更改。对 C 结构的任何更改或添加到公共接口将使新 API 不具备向后兼容性。
- 如果第一步中的 C_API_VERSION 已更改,或者 API 的哈希已更改,则需要更新 cversions.txt 文件。要检查哈希,请运行脚本 numpy/core/cversions.py 并注意打印的 API 哈希。如果该哈希与 numpy/core/code_generators/cversions.txt 中的最后一个哈希不匹配,则该哈希已更改。使用适当的 C_API_VERSION 和哈希,向 cversions.txt 添加一个新条目。如果 API 版本未更改,但哈希不同,则需要注释掉该 API 版本的先前条目。例如,在 NumPy 1.9 中添加了注释,这改变了哈希,但 API 与 1.8 中的相同。哈希用作 API 更改的检查,但不是确定性的。 如果步骤 1 和 2 正确执行,编译发布不会出现“在构建开始时检测到 API 不匹配”的警告。
- numpy/core/include/numpy/numpyconfig.h 将需要一个新的 NPY_X_Y_API_VERSION 宏,其中 X 和 Y 是发布的主要和次要版本号。只有在包含文件中的一些函数或宏已被废弃时,才需要将该宏的赋值与上一个版本的赋值增加。
numpy/core/setup_common.py 中的 C ABI 版本号仅应在主要发布中更新。
检查发布说明
使用 towncrier 构建发布说明并提交更改。这将删除所有来自doc/release/upcoming_changes
的片段,并添加doc/release/<version>-note.rst
。
towncrier 建立 –version “” git commit -m”创建发布说明”
检查发布说明是否最新。
在发布说明中更新一个“亮点”部分。提及以下一些内容:
- 主要新功能
- 已废弃和移除的功能
- 支持的 Python 版本
- 对于 SciPy,支持的 NumPy 版本
- 近期的展望
当前构建和发布信息
有用信息可在以下位置找到:
- 源代码树
- 安装说明
- pavement.py
- NumPy 文档
-
github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst
-
github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst
-
github.com/numpy/numpy/blob/main/doc/BRANCH_WALKTHROUGH.rst
-
- 发布脚本
github.com/numpy/numpy-vendor
支持的平台和版本
NEP 29 概述了支持的 Python 版本;2020 年上半年,这将是 Python >= 3.6。我们每次将代码合并到主分支时,都会针对所有这些版本进行 NumPy 测试。可能会为这些版本的子集提供二进制安装程序(请参阅下文)。
- OS X 支持的 OS X 版本 >= 10.9,有关 Python 版本支持,请参阅 NEP 29。我们为与 Python.org Python、系统 Python、homebrew 和 macports 兼容的 OSX 构建二进制 wheels - 有关详情,请参阅这个 OSX wheel 构建摘要。
- Windows 我们在 Windows 上构建 32 位和 64 位 wheels。支持 Windows 7、8 和 10。我们使用 mingw-w64 工具链、cibuildwheels 和 GitHub actions 构建 NumPy。
- Linux 我们为 NumPy 构建并发布 manylinux2014 wheels。许多 Linux 发行版包含其自己的 NumPy 二进制版本。
- BSD / Solaris 不提供二进制文件,但已报告在 Solaris 和 BSD 上成功构建。
工具链
我们在云基础设施上构建所有的 wheels - 因此,这个编译器列表仅供信息和本地调试构建使用。查看 numpy wheels 仓库中的 .travis.yml
脚本,获取使用 multibuild 的构建配方的已过时源。
编译器
目前,Python 在每个平台上构建时都使用与其相同的 gcc 版本。
- 目前,在 travis 上,OS X 构建使用 clang。从 travis-ci 的 OS X 10.9 虚拟机构建针对 Python.org 安装器的 Python >= 10.6 的二进制 wheels 似乎是安全的;
- Windows 构建使用 mingw-w64 工具链;
- Manylinux2014 wheels 使用 Manylinux docker 镜像中提供的 gcc。
你需要 Cython 来构建二进制文件。Cython 将 NumPy 分发中的 .pyx
文件编译为 .c
文件。
OpenBLAS
所有的组件链接到通过 openblas-libs 仓库提供的 OpenBLAS 版本。共享对象(或 DLL)随组件一起提供,并已重命名,以防止与可能存在于文件系统中的其他 OpenBLAS 共享对象发生名称冲突。
构建源存档和组件
NumPy 组件和源存档现在使用 github actions 进行 cibuildwheel 构建。
构建文档
我们不再构建 pdf 文件,只有 html 文档。需要上传到文档服务器的 numpy-html.zip
可以使用 spin docs dist
构建。
要将所需的文档构建依赖项安装到开发环境中,请运行 pip install -r doc_requirements.txt
。
上传到 PyPI
上传所需的唯一应用程序是
- twine (pip).
您还需要一个 PyPI 令牌,最好保存在钥匙链上。请参阅 twine keyring 文档了解如何做到这一点。
生成作者/PR 列表
您需要个人访问令牌 help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
,以便脚本可以访问 github NumPy 存储库。
- gitpython (pip)
- pygithub (pip)
编译器
在每个平台上都使用与 Python 本身构建时相同的 gcc 版本。目前这意味着:
- 目前在 travis 上构建的 OS X 使用 clang。似乎可以安全地从 travis-ci OSX 10.9 VMs 构建对 Python.org 安装程序中的 Python 的 OSX >= 10.6 的二进制组件;
- Windows 构建使用 mingw-w64 工具链;
- Manylinux2014 组件使用 Manylinux docker 映像中提供的 gcc。
您将需要 Cython 来构建二进制组件。Cython 将 NumPy 发行版中的 .pyx
文件编译为 .c
文件。
OpenBLAS
所有的组件链接到通过 openblas-libs 仓库提供的 OpenBLAS 版本。共享对象(或 DLL)随组件一起提供,并已重命名,以防止与可能存在于文件系统中的其他 OpenBLAS 共享对象发生名称冲突。
构建源存档和组件
NumPy 组件和源存档现在使用 github actions 进行 cibuildwheel 构建。
构建文档
我们不再构建 pdf 文件,只有 html 文档。需要上传到文档服务器的 numpy-html.zip
可以使用 spin docs dist
构建。
要将所需的文档构建依赖项安装到开发环境中,请运行 pip install -r doc_requirements.txt
。
上传到 PyPI
上传所需的唯一应用程序是
- twine (pip).
您还需要一个 PyPI 令牌,最好保存在钥匙链上。请参阅 twine keyring 文档了解如何做到这一点。
生成作者/PR 列表
你将需要一个个人访问令牌以便脚本可以访问 github NumPy 仓库help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
。
- gitpython (pip)
- pygithub (pip)
发行内容
- 轮子 我们当前支持 Python 3.8-3.10 在 Windows、OSX 和 Linux 上。
- Windows:使用 Github actions 构建的 32 位和 64 位轮子;
- OSX:使用 Github actions 构建的 x64_86 和 arm64 OSX 轮子;
- Linux:x64_86 和 aarch64 使用 Github actions 构建的 Manylinux2014 轮子。
- 其他 发行说明和更改日志
- 源分发 我们以 .tar.gz 格式构建源发布。
发行过程
对发布时间表达成一致意见
一个典型的发布时间表是一个 beta 版,两个候选发布版本和一个最终发布版。最好首先在邮件列表上讨论时间表,以便人们能够及时提交他们的代码,合并文档 wiki 编辑等。设定日期后,创建一个新的维护/x.y.z 分支,在主分支中为下一个版本添加新的空发布说明并更新 Trac 里程碑。
确保当前分支正确构建软件包
当 PR 标题以 REL
开头时,CI 会构建轮子。在发布前,你的最后一个 PR 应该标记为如此,并且所有测试都应该通过。你也可以做如下操作:
git clean -fxdq
python setup.py bdist_wheel
python setup.py sdist
有关构建过程的详细信息最好阅读下面的逐步说明。
注意
下列步骤将为 beta 版、候选发布版本和最终发布版本重复进行。
检查弃用
在 创建发布分支 之前,应该检查所有应该删除的弃用代码是否实际上已经删除,并且所有新的弃用都应该在文档字符串或弃用警告中说明代码将在哪个版本中被移除。
检查 C API 版本号
C API 版本需要在三个地方跟踪
- numpy/core/setup_common.py
- numpy/core/code_generators/cversions.txt
- numpy/core/include/numpy/numpyconfig.h
整个过程分为三个步骤。
- 如果 API 已更改,请在 setup_common.py 中递增 C_API_VERSION。只有当前 API 编译的任何代码都与上一个发布的 NumPy 版本向后兼容时,API 才不会更改。任何对 C 结构的更改或对公共接口的增加都会使新的 API 不向后兼容。
- 如果第一步中的 C_API_VERSION 已更改,或者 API 的哈希已更改,则需要更新 cversions.txt 文件。要检查哈希值,请运行 numpy/core/cversions.py 脚本,并注意打印的 API 哈希。如果该哈希与 numpy/core/code_generators/cversions.txt 中的最后一个哈希不匹配,则哈希已更改。使用适当的 C_API_VERSION 和哈希,将新条目添加到 cversions.txt。如果 API 版本没有更改,但哈希值不同,则需要注释掉以前针对该 API 版本的条目。例如,在 NumPy 1.9 中添加了注解,这更改了哈希值,但 API 与 1.8 中相同。哈希用作 API 更改的检查,但不是最终确定。 如果步骤 1 和 2 执行正确,编译发布版时不会出现“API 不匹配检测”的警告。
- numpy/core/include/numpy/numpyconfig.h 将需要一个新的 NPY_X_Y_API_VERSION 宏,其中 X 和 Y 是发布的主要和次要版本号。如果包含文件中的某些功能或宏已被弃用,则只需将分配给该宏的值从前一个版本递增即可。
numpy/core/setup_common.py 中的 C ABI 版本号应仅在主要发布版中进行更新。
检查发布说明
使用 towncrier 构建发布说明并提交更改。这将从 doc/release/upcoming_changes
中移除所有片段,并添加 doc/release/<version>-note.rst
。
towncrier build –version “” git commit -m”创建发布说明”
检查发布说明是否最新。
使用突出部分更新发布说明。提及以下一些内容:
- 主要新功能
- 弃用和删除的功能
- 支持的 Python 版本
- 对于 SciPy,支持的 NumPy 版本
- 近期展望
同意发布时间表
典型的发布时间表是一个 beta 版,两个候选发布版和一个最终发布版。最好首先在邮件列表中讨论时间安排,以便人们及时提交其提交,合并文档维基编辑等。确定日期后,创建新的 maintenance/x.y.z 分支,在主要分支中添加新的空的下一个版本的发布说明,并更新 Trac 里程碑。
确保当前分支正确构建软件包
当 PR 标题以 REL
开头时,CI 将构建 wheels。在发布之前,您的最后一个 PR 应标记为此,所有测试应通过。您也可以执行以下操作:
git clean -fxdq
python setup.py bdist_wheel
python setup.py sdist
对于构建过程本身的详细信息,最好阅读下面的逐步说明。
注意
以下步骤将重复适用于 beta 版、候选发布版和终版发布版。
检查废弃内容
在创建发布分支之前,应检查所有应该移除的废弃代码是否确实已移除,并且所有新的废弃代码都说在文档字符串或废弃警告中代码将在哪个版本中移除。
检查 C API 版本号
C API 版本需要在三个地方进行跟踪
- numpy/core/setup_common.py
- numpy/core/code_generators/cversions.txt
- numpy/core/include/numpy/numpyconfig.h
这个过程分为三个步骤。
- 如果 API 已更改,请在 setup_common.py 中增加 C_API_VERSION。只有当前 API 编译的任何代码与上一个发布的 NumPy 版本向后兼容时,API 才不会更改。对 C 结构的任何更改或公共接口的任何添加将使新 API 不向后兼容。
- 如果第一步中的 C_API_VERSION 已更改,或者 API 的哈希值已更改,则需要更新 cversions.txt 文件。要检查哈希值,请运行脚本 numpy/core/cversions.py,并注意打印的 API 哈希值。如果该哈希值与 numpy/core/code_generators/cversions.txt 中的最后一个哈希值不匹配,则表示哈希值已更改。使用适当的 C_API_VERSION 和哈希值,向 cversions.txt 添加新条目。如果 API 版本没有更改,但哈希值不同,则需要注释掉该 API 版本的先前条目。例如,在 NumPy 1.9 中添加了注释,这更改了哈希值,但 API 与 1.8 中的相同。哈希值用作 API 更改的检查,但并不是决定性的。 如果步骤 1 和步骤 2 正确完成,编译发布不应该出现警告“在构建开始时检测到 API 不匹配”。
- numpy/core/include/numpy/numpyconfig.h 将需要一个新的 NPY_X_Y_API_VERSION 宏,其中 X 和 Y 是发布的主要和次要版本号。只需增加此宏的值,如果包含文件中的一些函数或宏已被弃用。
numpy/core/setup_common.py 中的 C ABI 版本号应仅在主要版本发布时更新。
检查发布说明
使用towncrier创建发布说明并提交更改。这将从doc/release/upcoming_changes
中删除所有片段并添加doc/release/<version>-note.rst
。
towncrier build –version “” git commit -m”创建发布说明”
检查发布说明是否最新。
使用突出部分更新发布说明。提到以下一些内容:
- 主要新功能
- 弃用和移除的功能
- 支持的 Python 版本
- 对于 SciPy,支持的 NumPy 版本
- 展望不久的未来
逐步指导
这是在 Linux 上对 NumPy 1.21.0 版本的一次漫游,为了使用 GitHub Actions 和 cibuildwheels 进行构建,并上传到NumPy 的 anaconda.org 暂存库。这些命令可以复制到命令行中,但一定要确保用正确的版本替换 1.21.0。这应该与一般发布指南一起阅读。
设施准备
在开始制作发布之前,使用*_requirements.txt
文件确保您拥有所需的软件。大多数软件都可以使用 pip 安装,但有些将需要 apt-get、dnf 或您系统使用的其他软件。您还需要一个 GitHub 个人访问令牌(PAT)来推送文档。有几种方法可以简化流程:
- Git 可以设置使用密钥环来存储您的 GitHub 个人访问令牌。在网上搜索详细信息。
- 您可以使用
keyring
应用程序来存储 twine 的 PyPI 密码。有关详细信息,请参阅在线 twine 文档。
发布准备
添加/删除 Python 版本
添加或删除 Python 版本时,需要编辑三个文件:
- .github/workflows/wheels.yml # 用于 GitHub cibuildwheel
- .travis.yml # 用于 cibuildwheel aarch64 构建
- setup.py # 用于分类器和最低版本检查。
对于必要情况,这些更改应在普通的主分支 PR 中进行备份。使用*BLD:*前缀(构建标签)的提交摘要将导致 wheel 构建运行,因此更改将被测试。我们目前在 Python rc 发布后一旦 manylinux 和 cibuildwheel 支持它,就会对新的 Python 版本发布 wheels。对于 Python 3.11,我们能够在 rc1 公告发布一周后发布。
回溯拉取请求
已标记为此发布的更改必须被回溯到 maintenance/1.21.x 分支。
更新发布文档
在进行发布之前通常需要更新或创建四个文档:
- 更新记录
- 发布说明
-
.mailmap
文件 -
doc/source/release.rst
文件
这些更改应作为针对维护分支的普通 PR 进行。发布后,除了doc/source/release.rst
之外的所有文件都需要被前向移植到主分支。
生成更改日志
更改日志是使用更改日志工具生成的:
代码语言:javascript复制$ python tools/changelog.py $GITHUB v1.20.0..maintenance/1.21.x > doc/changelog/1.21.0-changelog.rst
其中GITHUB
包含您的 GitHub 访问令牌。文本将需要检查非标准的贡献者名称,并删除 dependabot 条目。最好删除可能存在于 PR 标题中的任何链接,因为它们在 markdown 中无法很好地转化,用等宽文本替换它们。非标准的贡献者名称应通过更新.mailmap
文件进行修正,这是一项大量的工作。最好在达到这一点之前进行几次试运行,并使用 GitHub 问题 ping 那些恶意行为者以获得所需的信息。
完成发布说明
如果这是一个系列中的第一个发布,将生成发布说明,请参阅doc/release/upcoming_changes/README.rst
中的发布说明以了解如何操作。生成发布说明也会删除doc/release/upcoming_changes/
中的所有新闻片段文件。
生成的发布说明始终需要一些修复,需要编写简介,并应该突出显示重大更改。对于补丁发布,changelog 文本可能也会被附加,但对于初始发布则不会,因为它太长了。查看以前的发布说明以了解如何操作。请注意,如果有顶部的 :orphan:
标记,则需要将其更改为 .. currentmodule:: numpy
,并需要更新 doc/source/release.rst
索引文件。
检查 pavement.py
文件
检查 pavement.py 文件是否指向了正确的发布说明。它应该在上次发布之后已经更新,但如果没有,请立即修复:
代码语言:javascript复制$ gvim pavement.py
发布的步骤
请注意,在下面的代码片段中,upstream
指的是 GitHub 上的根存储库,origin
指的是您个人 GitHub 存储库中的分支。如果您没有从存储库中派生出一个分支,而只是在本地克隆了它,您可能需要进行一些修改。您还可以编辑 .git/config
并添加 upstream
,如果它还没有出现的话。
1. 准备发布提交
检出发布的分支,确保它是最新的,并清理仓库:
代码语言:javascript复制$ git checkout maintenance/1.21.x
$ git pull upstream maintenance/1.21.x
$ git submodule update
$ git clean -xdfq
审查
代码语言:javascript复制$ python3 -m spin test -m full
给发布打上标签并推送标签。这需要对 numpy 仓库有写权限:
代码语言:javascript复制$ git tag -a -s v1.21.0 -m"NumPy 1.21.0 release"
$ git push upstream v1.21.0
如果您由于错误而需要删除标签:
代码语言:javascript复制$ git tag -d v1.21.0
$ git push --delete upstream v1.21.0
2. 构建 wheels
通过 cibuildwheel 构建 wheels(首选方法)
在此过程开始时标记构建将会触发会通过 cibuildwheel 构建 wheel 并将 wheels 和一个 sdist 上传到暂存库。在 github actions 上的 CI 运行(对于所有基于 x86 的和 macOS arm64 的 wheels)大约需要 1 1/4 小时。在 travis 上(对于 aarch64)的 CI 运行需要较少的时间。您可以在暂存库中检查已上传的文件,但请注意它与您所看到的运行任务的实时同步程度不是很高。
如果您希望手动触发一个 wheel 构建,可以这样做:
- 在 github actions -> Wheel builder 上有一个“Run workflow”的按钮,点击它并选择要构建的标签
- 在 travis 上有一个“More Options”的按钮,点击它并选择一个要构建的分支。似乎没有构建标签的选项。
如果一个 wheel 构建由于不相关原因失败,您可以单独重新运行它:
- 在 github actions 中选择Wheel builder点击包含要重新运行的构建的提交。在左边有一个 wheel 构建的列表,选择您要重新运行的构建,并在生成的页面上点击逆时针方向的箭头按钮。
- 在 travis 上选择失败的构建,这将带您进入该构建的 travis 作业。点击重新开始作业按钮。
请注意,如果您需要重新运行作业,则需要删除上传的文件(如果有的话),在 anaconda staging repository 中,旧文件不会被覆盖。
3. 下载轮子
当所有轮子成功构建并暂存后,使用 tools/download-wheels.py
脚本从 Anaconda 暂存目录下载它们:
$ cd ../numpy
$ mkdir -p release/installers
$ python3 tools/download-wheels.py 1.21.0
4. 生成 README 文件
这需要在所有安装程序都被下载后进行,但是在 pavement 文件更新为持续开发之前:
代码语言:javascript复制$ paver write_release
5. 将维护分支重置为开发状态(对于预发布版本跳过)
为下一个版本创建发布说明并编辑它们以设置版本。这些说明将是骨架,并且内容很少:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.21.1-notes.rst
$ gvim doc/source/release/1.21.1-notes.rst
$ git add doc/source/release/1.21.1-notes.rst
将新版本说明添加到文档发布列表中,并更新 pavement.py
中的 RELEASE_NOTES
变量:
$ gvim doc/source/release.rst pavement.py
提交结果:
代码语言:javascript复制$ git commit -a -m"REL: prepare 1.21.x for further development"
$ git push upstream HEAD
6. 上传到 PyPI
使用 twine
将其上传到 PyPI。最近的 PyPI 更改后需要一个最新版本的 twine
,这里使用的是版本 3.4.1
:
$ cd ../numpy
$ twine upload release/installers/*.whl
$ twine upload release/installers/numpy-1.21.0.tar.gz # Upload last.
如果其中一个命令在中途中断,您可能需要有选择地上传剩余的文件,因为 PyPI 不允许同一文件上传两次。应最后上传源文件以避免同步问题,这可能会导致 pip 用户在此过程中访问文件时出现 pip 从源代码构建而不是下载二进制 wheels。PyPI 仅允许单个源分发,这里我们选择了 zip 归档文件。
7. 将文件上传到 github
前往 github.com/numpy/numpy/releases
,应该有一个 v1.21.0 tag
,点击它并点击该标签的编辑按钮。有两种方法可以添加文件,使用可编辑的文本窗口和作为二进制上传。首先编辑从 rst 版本使用 pandoc 转换的 release/README.md
。需要修复的内容:如果包括,来自更改日志的 PR 行将被包装,需要解包,链接应改为等宽文本。然后将内容复制到剪贴板并粘贴到文本窗口中。可能需要多次尝试才能让它看起来正确。然后
- 将
release/installers/numpy-1.21.0.tar.gz
上传为二进制文件。 - 将
release/README.rst
上传为二进制文件。 - 将
doc/changelog/1.21.0-changelog.rst
上传为二进制文件。 - 如果这是一个预发布版本,请勾选预发布按钮。
- 在底部点击
{发布,更新}发布
按钮。
8. 将文档上传到 numpy.org(对于预发布跳过)
提醒
您将需要一个 GitHub 个人访问令牌来推送更新。
此步骤仅适用于最终发布,对于预发布和大多数补丁发布可以跳过。make merge-doc
会将 numpy/doc
仓库克隆到 doc/build/merge
,并使用新文档进行更新:
$ git clean -xdfq
$ git co v1.21.0
$ pushd doc
$ make docenv && source docenv/bin/activate
$ make merge-doc
$ pushd build/merge
如果发布系列是新的,您将需要在 doc/build/merge/index.html
首页的“insert here”注释下添加一个新部分:
$ gvim index.html /'insert here'
此外,更新 version-switcher json 文件以添加新版本并更新标记为*(稳定)*的版本:
代码语言:javascript复制$ gvim _static/versions.json
否则,只需将zip
链接更新为新的标签名称。由于我们不再生成pdf
文件,如果有,删除pdf
文件的行:
$ gvim index.html /'tag v1.21'
你可以在浏览器中“测试运行”新文档,以确保链接有效:
代码语言:javascript复制$ firefox index.html # or google-chrome, etc.
更新稳定的链接并更新:
代码语言:javascript复制$ ln -sfn 1.21 stable
$ ls -l # check the link
一切看起来令人满意之后,更新、提交并上传更改:
代码语言:javascript复制$ python3 update.py
$ git commit -a -m"Add documentation for v1.21.0"
$ git push
$ deactivate
$ popd
$ popd
9. 在 numpy.org 上发布发布公告(预发布时跳过)
假设你已经 fork 了github.com/numpy/numpy.org
:
$ cd ../numpy.org
$ git checkout main
$ git pull upstream main
$ git checkout -b announce-numpy-1.21.0
$ gvim content/en/news.md
- 对于所有发布,转到页面底部添加一个一行链接。查看以前的链接示例。
- 对于循环中的
*.0
发布,向顶部添加一个新的部分,简要描述新功能并将新闻链接指向它。
提交并推送:
代码语言:javascript复制$ git commit -a -m"announce the NumPy 1.21.0 release"
$ git push origin HEAD
转到你的 Github 分支并发起一个拉取请求。
10. 在邮件列表上发布公告
发布应该在 numpy-discussion、scipy-devel、scipy-user 和 python-announce-list 邮件列表上宣布。查看以前的公告获得基本模板。贡献者和 PR 列表与上面的发布说明生成的相同。如果你交叉发布,请确保 python-announce-list 是 BCC,这样答复不会发送到该列表。
11. 发布后任务(预发布时跳过)
检出 main 并推送文档更改:
代码语言:javascript复制$ git checkout -b post-1.21.0-release-update
$ git checkout maintenance/1.21.x doc/source/release/1.21.0-notes.rst
$ git checkout maintenance/1.21.x doc/changelog/1.21.0-changelog.rst
$ git checkout maintenance/1.21.x .mailmap # only if updated for release.
$ gvim doc/source/release.rst # Add link to new notes
$ git status # check status before commit
$ git commit -a -m"MAINT: Update main after 1.21.0 release."
$ git push origin HEAD
转到 GitHub 并发起一个 PR。
12. 更新 oldest-supported-numpy
如果这个版本是支持新 Python 版本的第一个版本,或者是提供新平台或 PyPy 版本的第一个版本,github.com/scipy/oldest-supported-numpy
中的版本固定应该被更新。要么提交带有setup.cfg
修改的 PR,要么提出一个需要改变信息的问题。
设施准备
在开始发布之前,请使用*_requirements.txt
文件确保你有所需的软件。大多数软件可以用 pip 安装,但有些需要 apt-get,dnf 或你的系统用于软件的任何内容。你还需要一个 GitHub 个人访问令牌(PAT)来推送文档。有几种方式可以简化事情:
- 可以设置 Git 来使用一个钥匙环来存储你的 GitHub 个人访问令牌。搜索网上的详细信息。
- 你可以使用
keyring
应用程序来存储 twine 的 PyPI 密码。请查看 twine 在线文档获取详细信息。
发布准备
添加/删除 Python 版本
在添加或删除 Python 版本时,需要编辑三个文件:
- .github/workflows/wheels.yml # 用于 github cibuildwheel
- .travis.yml # 用于 cibuildwheel aarch64 构建
- setup.py # 用于分类器和最低版本检查。
在主分支上制作这些更改,并且如有必要,则回溯。在提交摘要中使用 BLD: 前缀(构建标签)将导致运行 wheel 构建,以便测试更改。我们目前在首个 Python rc 之后发布新 Python 版本的 wheels,一旦 manylinux 和 cibuildwheel 支持它。对于 Python 3.11,我们能够在 rc1 发布后的一周内发布。
回溯 Pull Requests
已标记为此版本的更改必须回溯到 maintenance/1.21.x 分支。
更新发布文档
发布前通常需要更新或创建四个文档:
- changelog
- 发布说明
-
.mailmap
文件 -
doc/source/release.rst
文件
这些更改应作为针对 maintenance 分支的普通 PR 进行。发布后,除了 doc/source/release.rst
文件外,所有文件都需要向主分支合并。
生成 changelog
changelog 是使用 changelog 工具生成的:
代码语言:javascript复制$ python tools/changelog.py $GITHUB v1.20.0..maintenance/1.21.x > doc/changelog/1.21.0-changelog.rst
其中 GITHUB
包含您的 GitHub 访问令牌。需要检查文本以查找非标准的贡献者名称,并删除 dependabot 条目。此外,最好删除可能存在于 PR 标题中的任何链接,因为它们在转换为 Markdown 时表现不佳,用等宽文本替换它们。非标准的贡献者名称应通过更新 .mailmap
文件来修复,这是很多工作。最好在达到这一点之前进行几次试运行,并使用 GitHub 问题通知违规者获取所需的信息。
完成发布说明
如果这是系列中的第一个发布,将生成发布说明,请参阅 doc/release/upcoming_changes/README.rst
中的发布说明,以了解如何做到这一点。生成发布说明还将删除 doc/release/upcoming_changes/
中的所有新闻片段文件。
生成的发布说明始终需要一些修复,介绍需要撰写,并且重大更改应该被突出显示。对于补丁发布,changelog 文本也可以被附加,但对于初始发布则不用,因为太长了。查看以前的发布说明,以了解如何做到这一点。请注意,顶部的 :orphan:
标记(如果存在)将需要更改为 .. currentmodule:: numpy
,并且 doc/source/release.rst
索引文件将需要更新。
检查 pavement.py
文件
检查 pavement.py 文件是否指向正确的发布说明。它应该在上次发布后已被更新,但如果没有,请立即修复:
代码语言:javascript复制$ gvim pavement.py
添加/删除 Python 版本
当添加或删除 Python 版本时,需要编辑三个文件:
- .github/workflows/wheels.yml # 用于 github cibuildwheel
- .travis.yml # 用于 cibuildwheel aarch64 构建
- setup.py # 用于分类器和最低版本检查。
在普通 PR 中进行这些更改,并在必要时回溯。在提交摘要中使用*BLD:*前缀(构建标签)将导致运行轮子构建,以便进行测试,我们当前在 Python rc 发布后发布新 Python 版本的轮子,一旦 manylinux 和 cibuildwheel 支持它。对于 Python 3.11,我们能够在 rc1 发布公告后一周内发布。
回溯拉取请求
为本版本标记的更改必须回溯到 maintenance/1.21.x 分支。
更新发行文档
在发布之前通常需要更新或创建四个文档:
- 生成 changelog
- 发行说明
-
.mailmap
文件 -
doc/source/release.rst
文件
这些更改应作为普通 PR 针对 maintenance 分支进行。发布后,除doc/source/release.rst
之外的所有文件都需要被前向移植到 main 分支。
生成 changelog
生成 changelog 使用 changelog 工具:
代码语言:javascript复制$ python tools/changelog.py $GITHUB v1.20.0..maintenance/1.21.x > doc/changelog/1.21.0-changelog.rst
GITHUB
中包含您的 GitHub 访问令牌。需要检查文本中是否存在非标准贡献者名称,并删除 dependabot 条目。删除可能存在于 PR 标题中的任何链接也是个好主意,因为它们在 markdown 中翻译效果不佳,用单间隔文本替换它们。非标准贡献者名称应通过更新.mailmap
文件来修复,这是一项很多工作。最好在达到这一点之前进行几次试运行,并使用 GitHub 问题 ping 到恶意行为者以获取所需信息。
完成发行说明
如果这是系列中的第一个发布版本,则生成发行说明,请参阅doc/release/upcoming_changes/README.rst
中的发布说明查看如何完成此操作。生成发行说明也将删除doc/release/upcoming_changes/
中的所有新闻片段文件。
生成的发行说明总是需要一些修复,需要编写简介,并应指出重大更改。对于补丁版本,changelog 文本也可能被附加,但对于初始发布来说太长了。检查以前的发行说明可以看到这是如何完成的。注意,如果存在顶部的:orphan:
标记,需要改为.. currentmodule:: numpy
,并且需要更新doc/source/release.rst
索引文件。
检查pavement.py
文件
检查pavement.py
文件是否指向正确的发行说明。它应该在上次发布后已更新,但如果没有,现在修复它:
$ gvim pavement.py
生成 changelog
生成 changelog 使用 changelog 工具:
代码语言:javascript复制$ python tools/changelog.py $GITHUB v1.20.0..maintenance/1.21.x > doc/changelog/1.21.0-changelog.rst
其中 GITHUB
包含你的 GitHub 访问令牌。需要检查文本中是否有非标准的贡献者姓名,并删除 dependabot 的条目。此外,还应该删除 PR 标题中可能存在的任何链接,因为它们无法很好地转换为 Markdown,用等宽字体文本替换它们。非标准的贡献者姓名应该通过更新 .mailmap
文件进行修复,这是一项很大的工作。最好在达到这一点之前进行几次试验运行,并使用 GitHub issue 提醒犯错误的人获取所需信息。
完成发布说明
如果这是一个系列中的第一个发布,则生成发布说明,参见 doc/release/upcoming_changes/README.rst
中的发布说明如何生成。生成发布说明还会删除 doc/release/upcoming_changes/
中的所有 news fragment 文件。
生成的发布说明始终需要进行一些修正,需要编写简介,并突出显示重要更改。对于补丁发布,还可以追加更改日志文字,但对于初始发布则不需要,因为它太长了。查看以前的发布说明以了解如何处理。请注意,如果存在顶部的 :orphan:
标记,则需要更改为 .. currentmodule:: numpy
,并且需要更新 doc/source/release.rst
索引文件。
检查 pavement.py
文件
检查 pavement.py 文件是否指向了正确的发布说明。它应该在上次发布后进行了更新,但如果没有,请立即修复:
代码语言:javascript复制$ gvim pavement.py
发布步骤
注意,在下面的代码片段中,upstream
指的是 GitHub 上的根仓库,origin
指的是你个人 GitHub 仓库上的 fork。如果你没有 fork 仓库,而是仅仅在本地克隆了仓库,那么你可能需要进行调整。如果 .git/config
中没有 upstream
,你还可以编辑它并添加上。
1. 准备发布提交
检出发布的分支,确保它是最新的,并清除仓库:
代码语言:javascript复制$ git checkout maintenance/1.21.x
$ git pull upstream maintenance/1.21.x
$ git submodule update
$ git clean -xdfq
完整性检查:
代码语言:javascript复制$ python3 -m spin test -m full
给发布打标签并推送标签。这需要对 numpy 仓库有写入权限:
代码语言:javascript复制$ git tag -a -s v1.21.0 -m"NumPy 1.21.0 release"
$ git push upstream v1.21.0
如果需要删除由于错误而创建的标签:
代码语言:javascript复制$ git tag -d v1.21.0
$ git push --delete upstream v1.21.0
2. 构建 wheels
通过 cibuildwheel 构建 wheels(首选)
在这个过程开始时给构建打上标签,将会触发通过 cibuildwheel 构建 wheel 并将 wheels 和 sdist 上传到 staging 仓库。通过 github actions 进行的 CI 运行(针对所有基于 x86 的和 macOS 的 arm64 wheels)需要大约 1 1/4 小时。针对 aarch64 的 travis 上的 CI 运行所需时间较短。你可以在staging 仓库中检查上传的文件,但请注意它与正在运行的作业的运行情况不是非常同步。
如果希望手动触发构建 wheel,可以这样做:
- 在 github actions -> Wheel builder 中有一个“Run workflow”按钮,点击它并选择要构建的标签
- 在travis上有一个“更多选项”按钮,点击它并选择要构建的分支。看起来没有构建标签的选项。
如果因为与其它原因而导致轮子构建失败,您可以单独重新运行它:
- 在 github actions 中选择Wheel builder,点击包含您想重新运行的构建的提交。左侧有一个轮子构建列表,选择您想要重新运行的构建,在生成的页面上点击逆时针箭头按钮。
- 在travis上选择失败的构建,这将带您到该构建的 travis job。点击重新启动作业按钮。
请注意,如果确实需要重新运行作业,您需要删除 anaconda 分段存储库中已上传的文件。旧文件不会被覆盖。
3. 下载 wheels
当所有的 wheels 都已经成功构建并进行了分段处理后,使用tools/download-wheels.py
脚本从 Anaconda 分段目录下载它们:
$ cd ../numpy
$ mkdir -p release/installers
$ python3 tools/download-wheels.py 1.21.0
4. 生成 README 文件
这需要在下载所有安装程序之后完成,但在更新 pavement 文件以进行持续开发之前:
代码语言:javascript复制$ paver write_release
5. 将维护分支重置为开发状态(prereleases 可略过)
为下一个发布创建发布说明,并进行编辑以设置版本。这些说明将作为骨架,内容较少:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.21.1-notes.rst
$ gvim doc/source/release/1.21.1-notes.rst
$ git add doc/source/release/1.21.1-notes.rst
将新的发布说明添加到文档发布列表中,并更新pavement.py
中的RELEASE_NOTES
变量:
$ gvim doc/source/release.rst pavement.py
提交结果:
代码语言:javascript复制$ git commit -a -m"REL: prepare 1.21.x for further development"
$ git push upstream HEAD
6. 上传到 PyPI
使用twine
上传到 PyPI。最近 PyPI 更改后需要一个最新版本的twine
,这里使用的是版本3.4.1
:
$ cd ../numpy
$ twine upload release/installers/*.whl
$ twine upload release/installers/numpy-1.21.0.tar.gz # Upload last.
如果其中一个命令在中途中断,您可能需要选择性地上传剩余的文件,因为 PyPI 不允许上传相同的文件两次。应该最后上传源文件,以避免同步问题,当 pip 用户在此过程中访问文件时可能发生同步问题,导致 pip 构建源文件而非下载二进制 wheel。PyPI 只允许单个源分发, 在这里我们选择了 zip 归档。
7. 上传文件到 github
前往github.com/numpy/numpy/releases
,应该有一个v1.21.0 tag
,点击它并点击该标签的编辑按钮。有两种方式可以添加文件,一种是使用可编辑的文本窗口,另一种是使用二进制上传。首先编辑从 rst 版本使用 pandoc 翻译而来的release/README.md
。需要修复的问题:如果包括,来自修改日志的 PR 行被换行包裹,需要取消换行包裹,链接应改为等宽文本。然后将内容复制到剪贴板,粘贴到文本窗口中。可能需要尝试几次才能让它看起来正确。然后
- 上传
release/installers/numpy-1.21.0.tar.gz
作为二进制文件。 - 上传
release/README.rst
作为二进制文件。 - 上传
doc/changelog/1.21.0-changelog.rst
作为二进制文件。 - 如果这是预发布版本,请选中预发布按钮。
- 点击页面底部的
{Publish,Update} release
按钮。
8. 将文档上传到 numpy.org(跳过预发布)
注意
你需要一个 GitHub 个人访问令牌来推送更新。
这个步骤只适用于最终发布,对于预发布和大多数补丁发布,可以跳过make merge-doc
克隆numpy/doc
存储库到doc/build/merge
并使用新文档更新它:
$ git clean -xdfq
$ git co v1.21.0
$ pushd doc
$ make docenv && source docenv/bin/activate
$ make merge-doc
$ pushd build/merge
如果发布系列是新的,你需要在“insert here”注释后立即在doc/build/merge/index.html
首页添加一个新的章节:
$ gvim index.html /'insert here'
此外,更新版本切换器 json 文件以添加新版本并更新标记为*(stable)*的版本:
代码语言:javascript复制$ gvim _static/versions.json
否则,只有zip
链接应该使用新的标签名称更新。由于我们不再生成pdf
文件,如果存在的话,删除pdf
文件的行:
$ gvim index.html /'tag v1.21'
你可以在浏览器中“测试运行”新文档,确保链接有效:
代码语言:javascript复制$ firefox index.html # or google-chrome, etc.
更新稳定链接和更新:
代码语言:javascript复制$ ln -sfn 1.21 stable
$ ls -l # check the link
一切看起来令人满意后,更新、提交和上传更改:
代码语言:javascript复制$ python3 update.py
$ git commit -a -m"Add documentation for v1.21.0"
$ git push
$ deactivate
$ popd
$ popd
9. 在 numpy.org 上宣布发布(跳过预发布)
这假设您已经 fork 了github.com/numpy/numpy.org
:
$ cd ../numpy.org
$ git checkout main
$ git pull upstream main
$ git checkout -b announce-numpy-1.21.0
$ gvim content/en/news.md
- 对于所有发布版本,转到页面底部并添加一行链接。看看以前的链接作为例子。
- 对于循环中的
*.0
版本,在顶部添加一个新的章节,并简要介绍新功能,并将新闻链接指向它。
提交并推送:
代码语言:javascript复制$ git commit -a -m"announce the NumPy 1.21.0 release"
$ git push origin HEAD
转到你的 Github 分支并创建一个 PR。
10. 在邮件列表中宣布
发布应该在 numpy-discussion, scipy-devel, scipy-user 和 python-announce-list 邮件列表上宣布。查看以前的公告以获取基本模板。贡献者和 PR 列表与上面生成的发布说明相同。如果交叉发布,请确保 python-announce-list 是 BCC,这样回复将不会发送到该列表。
11. 发布后任务(跳过预发布)
切换到主分支并向前推送文档更改:
代码语言:javascript复制$ git checkout -b post-1.21.0-release-update
$ git checkout maintenance/1.21.x doc/source/release/1.21.0-notes.rst
$ git checkout maintenance/1.21.x doc/changelog/1.21.0-changelog.rst
$ git checkout maintenance/1.21.x .mailmap # only if updated for release.
$ gvim doc/source/release.rst # Add link to new notes
$ git status # check status before commit
$ git commit -a -m"MAINT: Update main after 1.21.0 release."
$ git push origin HEAD
转到 GitHub 并创建 PR。
12. 更新 oldest-supported-numpy
如果此发布是第一个支持新的 Python 版本,或者第一个为新平台或 PyPy 版本提供 wheels 的版本,应该更新github.com/scipy/oldest-supported-numpy
中的版本设置。要么提交带有setup.cfg
更改的 PR,要么发布一个包含所需更改信息的问题。
1. 准备发布提交
切换到发布分支,确保它是最新的,并清理存储库:
代码语言:javascript复制$ git checkout maintenance/1.21.x
$ git pull upstream maintenance/1.21.x
$ git submodule update
$ git clean -xdfq
检查:
代码语言:javascript复制$ python3 -m spin test -m full
给发布打上标签并推送标签。这需要对 numpy 存储库的写入权限:
代码语言:javascript复制$ git tag -a -s v1.21.0 -m"NumPy 1.21.0 release"
$ git push upstream v1.21.0
如果需要因错误删除标签:
代码语言:javascript复制$ git tag -d v1.21.0
$ git push --delete upstream v1.21.0
2. 构建 wheels
通过 cibuildwheel 构建 wheels(首选)
在此过程开始时对构建进行标记将通过 cibuildwheel 触发一个轮子构建,并将轮子和 sdist 上传到暂存仓库。 在 github actions 上进行的 CI 运行(对所有基于 x86 和 macOS 的 arm64 轮子)大约需要 1 1/4 小时。 在 travis 上进行的 CI 运行(对 aarch64)需要更少的时间。 您可以在暂存存储库上检查已上传的文件,但请注意它与运行中作业显示的内容不完全同步。
如果您希望手动触发轮子构建,可以执行以下操作:
- 在 github actions -> Wheel builder 上有一个“运行工作流”按钮,点击它并选择要构建的标签。
- 在travis 上有一个“更多选项”按钮,点击它并选择要构建的分支。 似乎没有选项可以构建标签。
如果轮子构建由于不相关原因失败,您可以单独重新运行它:
- 在 github actions 上选择 Wheel builder 点击包含您想要重新运行的构建的提交。 左侧有一个轮子构建的列表,选择您想要重新运行的构建,然后在结果页面上点击逆时针箭头按钮。
- 在travis 上选择失败的构建,这将带您进入该构建的 travis 作业。 大家点击重新运行作业按钮。
请注意,如果您确实需要重新运行作业,您需要删除 anaconda 暂存存储库 中已上传的文件(如果有)。 旧文件将不会被覆盖。
通过 cibuildwheel 构建轮子(首选)
在此过程开始时对构建进行标记将通过 cibuildwheel 触发一个轮子构建,并将轮子和 sdist 上传到暂存仓库。 在 github actions 上进行的 CI 运行(对所有基于 x86 和 macOS 的 arm64 轮子)大约需要 1 1/4 小时。 在 travis 上进行的 CI 运行(对 aarch64)需要更少的时间。 您可以在暂存存储库上检查已上传的文件,但请注意它与运行中作业显示的内容不完全同步。
如果您希望手动触发轮子构建,可以执行以下操作:
- 在 github actions -> Wheel builder 上有一个“运行工作流”按钮,点击它并选择要构建的标签。
- 在travis 上有一个“更多选项”按钮,点击它并选择要构建的分支。 似乎没有选项可以构建标签。
如果轮子构建由于不相关原因失败,您可以单独重新运行它:
- 在 github 动作中选择Wheel builder,点击包含您要重新运行的构建的提交。在左侧有一个轮子构建列表,选择您要重新运行的构建,在生成的页面上点击逆时针箭头按钮。
- 在travis上选择失败的构建,这将带您到该构建的 travis 作业。点击重新开始作业按钮。
注意,如果需要重新运行作业,您需要删除在 anaconda 的存储库中上传的任何文件。旧文件将不会被覆盖。
3. 下载轮子
当所有轮子都成功构建并暂存时,使用tools/download-wheels.py
脚本从 Anaconda 暂存目录下载它们:
$ cd ../numpy
$ mkdir -p release/installers
$ python3 tools/download-wheels.py 1.21.0
4. 生成 README 文件
这需要在下载所有安装程序之后完成,但在更新 pavement 文件以继续开发之前完成:
代码语言:javascript复制$ paver write_release
5. 将维护分支重置为开发状态(预发布跳过)
为下一个发布创建发布说明,并编辑以设置版本。这些说明将是一个骨架,并且内容很少:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.21.1-notes.rst
$ gvim doc/source/release/1.21.1-notes.rst
$ git add doc/source/release/1.21.1-notes.rst
添加新发布说明到文档发布列表中,并更新pavement.py
中的RELEASE_NOTES
变量:
$ gvim doc/source/release.rst pavement.py
提交结果:
代码语言:javascript复制$ git commit -a -m"REL: prepare 1.21.x for further development"
$ git push upstream HEAD
6. 上传到 PyPI
使用twine
上传到 PyPI。由于 PyPI 最近的更改,需要使用最新版本的twine
,此处使用的版本是3.4.1
:
$ cd ../numpy
$ twine upload release/installers/*.whl
$ twine upload release/installers/numpy-1.21.0.tar.gz # Upload last.
如果其中一个命令在中间中断,您可能需要选择性地上传剩余的文件,因为 PyPI 不允许相同的文件上传两次。为了避免同步问题,最后应该上传源文件,即使 pip 用户在此过程中访问文件,也不会引起从源代码构建而不是下载二进制轮子。PyPI 只允许单个源分发,我们选择了 zip 存档。
7. 将文件上传到 github
转到github.com/numpy/numpy/releases
,那里应该有一个v1.21.0 tag
,点击它并点击该标签的编辑按钮。有两种方法可以添加文件,一种是使用可编辑的文本窗口,另一种是使用二进制上传。首先编辑从 rst 版本使用 pandoc 翻译的release/README.md
。需要修复的问题:如果包括 PR 行,则需要调整,链接应更改为等宽文本。然后复制内容到剪贴板,并粘贴到文本窗口中。可能需要多次尝试才能让它看起来正确。然后
- 以二进制文件上传
release/installers/numpy-1.21.0.tar.gz
。 - 以二进制文件上传
release/README.rst
。 - 以二进制文件上传
doc/changelog/1.21.0-changelog.rst
。 - 如果这是一个预发布版本,请勾选预发布按钮。
- 在底部点击
{发布,更新}发布
按钮。
8. 将文档上传到 numpy.org(预发布跳过)
注意
您将需要 GitHub 个人访问令牌来推送更新。
此步骤仅适用于最终发布,并可跳过预发布和大多数补丁发布。 make merge-doc
将 numpy/doc
存储库克隆到 doc/build/merge
并使用新文档更新它:
$ git clean -xdfq
$ git co v1.21.0
$ pushd doc
$ make docenv && source docenv/bin/activate
$ make merge-doc
$ pushd build/merge
如果发布系列是新的,则需要在 doc/build/merge/index.html
首页的“在此处插入”注释后添加新的部分:
$ gvim index.html /'insert here'
此外,更新版本切换器 json 文件以添加新版本并更新标记为 (稳定) 的版本:
代码语言:javascript复制$ gvim _static/versions.json
否则,仅应使用新的标记名称更新 zip
链接。由于我们不再生成 pdf
文件,如果存在,删除 pdf
文件的行:
$ gvim index.html /'tag v1.21'
您可以在浏览器中“测试运行”新文档,以确保链接正常:
代码语言:javascript复制$ firefox index.html # or google-chrome, etc.
更新稳定链接并更新:
代码语言:javascript复制$ ln -sfn 1.21 stable
$ ls -l # check the link
一切看起来令人满意后,更新、提交并上传更改:
代码语言:javascript复制$ python3 update.py
$ git commit -a -m"Add documentation for v1.21.0"
$ git push
$ deactivate
$ popd
$ popd
9. 在 numpy.org 上宣布发布(跳过预发布)
这假设您已经派生了 github.com/numpy/numpy.org
:
$ cd ../numpy.org
$ git checkout main
$ git pull upstream main
$ git checkout -b announce-numpy-1.21.0
$ gvim content/en/news.md
- 对于所有发布版本,请转到页面底部并添加一行链接。参考以前的链接示例。
- 对于循环中的
*.0
发布,在顶部添加一个新特性的简短描述并将新闻链接指向它。
提交并推送:
代码语言:javascript复制$ git commit -a -m"announce the NumPy 1.21.0 release"
$ git push origin HEAD
前往您的 Github 派生版本并提出拉取请求。
10. 在邮件列表上宣布
发布应该在 numpy-discussion、scipy-devel、scipy-user 和 python-announce-list 邮件列表上宣布。查看以前的公告以获取基本模板。贡献者和 PR 列表与上述发布说明生成的相同。如果跨帖,请确保 python-announce-list 是密件抄送,以便回复不会发送到该列表。
11. 发布后任务(对于预发布,请跳过)
检出主分支并将文档更改向前移植:
代码语言:javascript复制$ git checkout -b post-1.21.0-release-update
$ git checkout maintenance/1.21.x doc/source/release/1.21.0-notes.rst
$ git checkout maintenance/1.21.x doc/changelog/1.21.0-changelog.rst
$ git checkout maintenance/1.21.x .mailmap # only if updated for release.
$ gvim doc/source/release.rst # Add link to new notes
$ git status # check status before commit
$ git commit -a -m"MAINT: Update main after 1.21.0 release."
$ git push origin HEAD
前往 GitHub 并创建一个 PR。
12. 更新 oldest-supported-numpy
如果此版本是第一个支持新的 Python 版本,或者第一个为新平台或 PyPy 版本提供 wheels,那么github.com/scipy/oldest-supported-numpy
中的版本固定应该更新。要么提交对那里的 setup.cfg
的更改的 PR,要么在需要更改的信息上开启一个问题。
分支演示
本指南包含在 Linux 上分支 NumPy 1.21.x 的步骤。可以将命令复制到命令行中,但一定要将 1.21 和 1.22 替换为正确的版本。在制作分支之前,尽可能使 .mailmap
最新,这可能需要几周时间。
这应与通用发布指南一起阅读。
分支
制作分支
仅在启动新的维护分支时才需要。因为 NumPy 现在依赖于标签来确定版本,所以在主分支中启动新的开发周期需要一个带注释的标签。操作如下:
代码语言:javascript复制$ git checkout main
$ git pull upstream main
$ git commit --allow-empty -m'REL: Begin NumPy 1.22.0 development'
$ git push upstream HEAD
如果推送失败,因为新的 PR 已经合并,执行以下操作:
代码语言:javascript复制$ git pull --rebase upstream
并重复推送。一旦推送成功,对其进行标记:
代码语言:javascript复制$ git tag -a -s v1.22.0.dev0 -m'Begin NumPy 1.22.0 development'
$ git push upstream v1.22.0.dev0
然后创建新分支并推送它:
代码语言:javascript复制$ git branch maintenance/1.21.x HEAD^
$ git push upstream maintenance/1.21.x
为主分支做进一步的开发准备
创建一个 PR 分支来为主分支做进一步的开发准备:
代码语言:javascript复制$ git checkout -b 'prepare-main-for-1.22.0-development' v1.22.0.dev0
删除发布注释片段:
代码语言:javascript复制$ git rm doc/release/upcoming_changes/[0-9]*.*.rst
创建新的发布注释框架并添加到索引中:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release/1.22.0-notes.rst # put the correct version
$ git add doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release.rst # add new notes to notes index
$ git add doc/source/release.rst
更新pavement.py
,并将RELEASE_NOTES
变量更新为指向新的注释:
$ gvim pavement.py
$ git add pavement.py
更新cversions.txt
以添加当前发布。在这个早期阶段不用担心新的哈希,只需按照以前的惯例添加注释即可:
$ gvim numpy/core/code_generators/cversions.txt
$ git add numpy/core/code_generators/cversions.txt
检查你的工作,提交并推送:
代码语言:javascript复制$ git status # check work
$ git commit -m'REL: Prepare main for NumPy 1.22.0 development'
$ git push origin HEAD
现在创建一个拉取请求。
分支
创建分支
仅在启动新的维护分支时需要这样做。因为 NumPy 现在依赖标签来确定版本,所以在主分支中开始新的开发周期需要有一个带注释的标签。操作如下:
代码语言:javascript复制$ git checkout main
$ git pull upstream main
$ git commit --allow-empty -m'REL: Begin NumPy 1.22.0 development'
$ git push upstream HEAD
如果推送失败,因为新的 PR 已经合并,执行以下操作:
代码语言:javascript复制$ git pull --rebase upstream
并重复推送。一旦推送成功,对其进行标记:
代码语言:javascript复制$ git tag -a -s v1.22.0.dev0 -m'Begin NumPy 1.22.0 development'
$ git push upstream v1.22.0.dev0
然后创建新分支并推送:
代码语言:javascript复制$ git branch maintenance/1.21.x HEAD^
$ git push upstream maintenance/1.21.x
为主分支做进一步的开发准备
创建一个 PR 分支来为主分支做进一步的开发准备:
代码语言:javascript复制$ git checkout -b 'prepare-main-for-1.22.0-development' v1.22.0.dev0
删除发布注释片段:
代码语言:javascript复制$ git rm doc/release/upcoming_changes/[0-9]*.*.rst
创建新的发布注释框架并添加到索引中:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release/1.22.0-notes.rst # put the correct version
$ git add doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release.rst # add new notes to notes index
$ git add doc/source/release.rst
更新pavement.py
,并将RELEASE_NOTES
变量更新为指向新的注释:
$ gvim pavement.py
$ git add pavement.py
更新cversions.txt
以添加当前发布。在这个早期阶段不用担心新的哈希,只需按照以前的惯例添加注释即可:
$ gvim numpy/core/code_generators/cversions.txt
$ git add numpy/core/code_generators/cversions.txt
检查你的工作,提交并推送:
代码语言:javascript复制$ git status # check work
$ git commit -m'REL: Prepare main for NumPy 1.22.0 development'
$ git push origin HEAD
现在创建一个拉取请求。
创建分支
仅在启动新的维护分支时需要这样做。因为 NumPy 现在依赖标签来确定版本,所以在主分支中开始新的开发周期需要有一个带注释的标签。操作如下:
代码语言:javascript复制$ git checkout main
$ git pull upstream main
$ git commit --allow-empty -m'REL: Begin NumPy 1.22.0 development'
$ git push upstream HEAD
如果推送失败,因为新的 PR 已经合并,执行以下操作:
代码语言:javascript复制$ git pull --rebase upstream
并重复推送。一旦推送成功,对其进行标记:
代码语言:javascript复制$ git tag -a -s v1.22.0.dev0 -m'Begin NumPy 1.22.0 development'
$ git push upstream v1.22.0.dev0
然后创建新分支并推送它:
代码语言:javascript复制$ git branch maintenance/1.21.x HEAD^
$ git push upstream maintenance/1.21.x
为主分支做进一步的开发准备
创建一个 PR 分支来为主分支做进一步的开发准备:
代码语言:javascript复制$ git checkout -b 'prepare-main-for-1.22.0-development' v1.22.0.dev0
删除发布注释片段:
代码语言:javascript复制$ git rm doc/release/upcoming_changes/[0-9]*.*.rst
创建新的发布注释框架并添加到索引中:
代码语言:javascript复制$ cp doc/source/release/template.rst doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release/1.22.0-notes.rst # put the correct version
$ git add doc/source/release/1.22.0-notes.rst
$ gvim doc/source/release.rst # add new notes to notes index
$ git add doc/source/release.rst
更新pavement.py
,并将RELEASE_NOTES
变量更新为指向新的注释:
$ gvim pavement.py
$ git add pavement.py
更新cversions.txt
以添加当前发布。在这个早期阶段不用担心新的哈希,只需按照以前的惯例添加注释即可:
$ gvim numpy/core/code_generators/cversions.txt
$ git add numpy/core/code_generators/cversions.txt
检查你的工作,提交并推送:
代码语言:javascript复制$ git status # check work
$ git commit -m'REL: Prepare main for NumPy 1.22.0 development'
$ git push origin HEAD
现在创建一个拉取请求。