设置和使用您的开发环境#

使用虚拟环境#

一个常见的问题是“如何并行设置开发版本的 NumPy 和我用于工作/研究的发行版本?”

实现此目标的一种简单方法是使用 pip 或 conda 等工具将发行版本安装到 site-packages 中,并在虚拟环境中设置开发版本。

如果您使用 conda,我们建议使用 repo 根目录中的 environment.yml 文件为 numpy 开发创建一个单独的虚拟环境(这将创建环境并一次性安装所有开发依赖项)

$ conda env create -f environment.yml  # `mamba` works too for this command
$ conda activate numpy-dev

如果您使用的方法不是 conda 安装的 Python,请首先安装 virtualenv(可以选择使用 virtualenvwrapper),然后创建您的虚拟环境(此处命名为 numpy-dev),激活它,并使用以下命令安装所有项目依赖项:

$ virtualenv numpy-dev
$ source numpy-dev/bin/activate # activate virtual environment
$ python -m pip install -r requirements/all_requirements.txt

现在,每当您想切换到虚拟环境时,可以使用命令 source numpy-dev/bin/activate,并使用 deactivate 退出虚拟环境并返回到您之前的 shell。

从源代码构建#

请参阅 从源代码构建

测试构建#

在运行测试之前,请先安装测试依赖项:

$ python -m pip install -r requirements/test_requirements.txt
$ python -m pip install asv # only for running benchmarks

要构建 NumPy 的开发版本并运行测试,请使用 spin 实用程序生成具有正确设置的 Python 导入路径等的交互式 shell。要运行测试,请执行以下操作之一:

$ spin test -v
$ spin test numpy/random  # to run the tests in a specific module
$ spin test -v -t numpy/_core/tests/test_nditer.py::test_iter_c_order

这将首先构建 NumPy,因此第一次可能需要几分钟。

您还可以使用 spin bench 进行基准测试。有关更多命令行选项,请参阅 spin --help

注意

如果上述命令导致 RuntimeError: Cannot parse version 0+untagged.xxxxx,请运行 git pull upstream main --tags

可以通过在裸 -- 后传递额外参数,将额外参数转发到 pytest。例如,要使用转发到目标的 --pdb 标志运行测试方法,请运行以下命令:

$ spin test -t numpy/tests/test_scripts.py::test_f2py -- --pdb

您还可以通过将 -k 参数传递给 pytest 来使用 python 运算符匹配测试名称

$ spin test -v -t numpy/_core/tests/test_multiarray.py -- -k "MatMul and not vector"

要运行“doctests”(检查文档中的代码示例是否正确),请使用 check-docs spin 命令。它依赖于 scipy-docs 包,该包在标准库 doctest 包的基础上提供了几个附加功能。安装 scipy-doctest 并运行以下命令之一:

$ spin check-docs -v
$ spin check-docs numpy/linalg
$ spin check-docs -v -- -k 'det and not slogdet'

注意

请记住,在提交更改之前,NumPy 的所有测试都应该通过。

注意

测试套件中的一些测试需要大量的内存,如果您的系统内存不足,则会跳过这些测试。

其他构建选项#

有关更多选项,包括选择编译器、设置自定义编译器标志和控制并行性,请参阅 编译器选择和自定义构建(来自 SciPy 文档)。

运行测试#

除了使用 spin 之外,还有多种方法可以运行测试。在解释器内部,测试可以这样运行:

>>> np.test()  
>>> np.test('full')   # Also run tests marked as slow
>>> np.test('full', verbose=2)   # Additionally print test name/file

An example of a successful test :
``4686 passed, 362 skipped, 9 xfailed, 5 warnings in 213.99 seconds``

或者从命令行使用类似的方法:

$ python -c "import numpy as np; np.test()"

测试也可以使用 pytest numpy 运行,但是 NumPy 特定的插件找不到,这会导致奇怪的副作用。

运行单个测试文件很有用;它比运行整个测试套件或整个模块的测试套件快得多(例如:np.random.test())。这可以使用以下命令完成:

$ python path_to_testfile/test_file.py

它也接受额外的参数,例如 --pdb,当测试失败或引发异常时,它会将您放入 Python 调试器中。

还支持使用 tox 运行测试。例如,要使用 Python 3.9 构建 NumPy 并运行测试套件,请使用:

$ tox -e py39

有关更详细的信息,请参阅 测试指南

注意:不要在没有 spin 的情况下从 numpy git 仓库的根目录运行测试,这会导致奇怪的测试错误。

运行代码风格检查#

可以对新添加的 Python 代码行执行代码风格检查。

使用 pip 安装所有依赖包:

$ python -m pip install -r requirements/linter_requirements.txt

要在提交新代码之前运行代码风格检查,请运行:

$ python tools/linter.py

要检查当前分支与目标分支中新添加的 Python 代码的所有更改,请运行:

$ python tools/linter.py --branch main

如果没有错误,脚本将退出而不会显示任何消息。如果出现错误,请检查错误消息以了解详细信息。

$ python tools/linter.py --branch main
./numpy/_core/tests/test_scalarmath.py:34:5: E303 too many blank lines (3)
1       E303 too many blank lines (3)

建议在将提交推送到远程分支之前运行代码风格检查,因为代码风格检查器会在 CI 管道中运行。

有关样式指南的更多详细信息

重建和清理工作区#

在对编译代码进行更改后,可以使用与之前使用的相同的构建命令来重建 NumPy - 只有更改的文件将被重建。进行完整的构建(有时是必要的)需要先清理工作区。执行此操作的标准方法是(*注意:这会删除所有未提交的文件!*):

$ git clean -xdf

当您想要丢弃所有更改并返回到 repo 中的上次提交时,可以使用以下命令之一:

$ git checkout .
$ git reset --hard

调试#

另一个常见的问题是“如何调试 NumPy 中的 C 代码?”。首先,确保您已在系统上安装了带有 Python 扩展的 gdb(通常是 Linux 系统的默认设置)。您可以查看 gdb 中运行的 Python 版本以验证您的设置:

(gdb) python
>import sys
>print(sys.version_info)
>end
sys.version_info(major=3, minor=7, micro=0, releaselevel='final', serial=0)

大多数 Python 版本不包含调试符号,并且使用启用了编译器优化的方式构建。为了获得最佳调试体验,建议使用 Python 的调试版本进行构建,请参阅高级调试工具

在调试方面,NumPy 也需要以调试模式构建。您需要使用debug构建类型并禁用优化以确保在对象构建期间使用-O0标志。请注意,在使用spin build命令构建之前,不应在您的环境中安装 NumPy。

要在构建过程中生成源代码级别的调试信息,请运行:

$ spin build --clean -- -Dbuildtype=debug -Ddisable-optimization=true

注意

如果您使用的是 conda 环境,请注意 conda 会自动设置CFLAGSCXXFLAGS,它们默认情况下将包含-O2标志。您可以安全地使用unset CFLAGS && unset CXXFLAGS来避免它们,或者在spin命令的开头提供它们:CFLAGS="-O0 -g" CXXFLAGS="-O0 -g"。或者,为了更永久地控制这些变量,您可以在<path-to-conda-envs>/numpy-dev/etc/conda/activate.d目录中创建env_vars.sh文件。在这个文件中,您可以导出CFLAGSCXXFLAGS变量。有关完整说明,请参考https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#saving-environment-variables

接下来,您需要编写一个 Python 脚本,调用您想要调试其执行的 C 代码。例如mytest.py

import numpy as np
x = np.arange(5)
np.empty_like(x)

请注意,您的测试文件需要位于您拥有的 NumPy 克隆之外。现在,您可以运行:

$ spin gdb /path/to/mytest.py

如果您使用的是 clang 工具链:

$ spin lldb /path/to/mytest.py

然后在调试器中:

(gdb) break array_empty_like
(gdb) run

lldb 对等项:

(lldb) breakpoint set --name array_empty_like
(lldb) run

执行现在将停止在相应的 C 函数处,您可以像往常一样逐步执行它。可以使用许多有用的 Python 特定命令。例如,要查看您在 Python 代码中的位置,请使用py-list,要查看 Python 回溯,请使用py-bt。有关更多详细信息,请参阅DebuggingWithGdb。以下是一些常用的命令:

  • list:列出指定的函数或行。

  • next:单步执行程序,继续执行子程序调用。

  • step:在信号或断点后继续调试程序。

  • print:打印表达式 EXP 的值。

对 Python 调试的丰富支持要求 Python 分发的python-gdb.py脚本安装在 gdb 可以找到它的路径中。如果您从系统包管理器安装了 Python 构建版本,则您可能不需要手动执行任何操作。但是,如果您从源代码构建了 Python,则您可能需要在您的主目录中创建一个.gdbinit文件,指向 Python 安装位置的 gdb。例如,通过pyenv安装的 Python 版本需要一个包含以下内容的.gdbinit文件:

add-auto-load-safe-path ~/.pyenv

强烈建议使用带有调试支持的 Python(在 Linux 发行版中通常打包为python-dbg)构建 NumPy。

理解代码 & 入门#

更好地理解代码库的最佳策略是选择您想要更改的内容,并开始阅读代码以了解其工作原理。如有疑问,您可以在邮件列表中提问。即使您的拉取请求并不完美,也没有关系,社区总是乐于助人。作为一个志愿者项目,事情有时会被搁置,如果您在两到四周内没有收到回复,可以随时联系我们。

因此,请继续选择一些让您烦恼或困惑的 NumPy 内容,试验代码,参与讨论或阅读参考文档以尝试修复它。事情会逐渐明朗,很快您就会对整个项目有相当好的理解。祝您好运!