设置和使用你的开发环境#
推荐的开发设置#
由于 NumPy 包含用 C 和 Cython 编写的部分,这些部分需要在使用之前进行编译,请确保你已安装必要的编译器和 Python 开发头文件 - 请参阅 从源代码构建。从版本 2.0
开始,构建 NumPy 需要符合 C11 和 C++17 标准的编译器。
编译代码还意味着从开发源代码导入 NumPy 需要一些额外的步骤,这些步骤将在下面解释。本章的其余部分假设你已按照 使用 scikit-image 源代码 中的说明设置了你的 git 仓库。
注意
如果你在从源代码构建 NumPy 或设置本地开发环境时遇到问题,可以尝试使用 GitHub Codespaces 构建 NumPy。它允许你直接在浏览器中创建正确的开发环境,减少了安装本地开发环境和处理不兼容依赖项的需要。
如果你拥有良好的互联网连接并且想要一个临时设置,那么在 Codespaces 环境中使用 NumPy 通常更快。有关如何开始使用 Codespaces 的文档,请参阅 Codespaces 文档。在为 numpy/numpy
仓库创建 Codespace 时,默认的 2 核机器类型有效;4 核机器会更快地构建和工作(但当然会以消耗你一半的免费使用时间为代价)。你的 Codespace 启动后,你可以运行 conda activate numpy-dev
,你的开发环境将完全设置好 - 然后你可以按照 NumPy 文档中的相关部分构建、测试、开发、编写文档并为 NumPy 做出贡献。
使用虚拟环境#
一个经常被问到的问题是“我如何并行设置 NumPy 的开发版本以及我用来完成工作/研究的已发布版本?”
实现这一点的一种简单方法是在 site-packages 中安装已发布的版本,例如使用 pip 或 conda,并在虚拟环境中设置开发版本。
如果你使用 conda,我们建议使用仓库根目录中的 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
你还可以 使用 Python 运算符匹配测试名称,方法是将 -k
参数传递给 pytest
$ 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 运行测试。例如,要构建 NumPy 并使用 Python 3.9 运行测试套件,请使用
$ tox -e py39
有关更详细的信息,请参阅 测试指南。
注意:不要在没有 spin
的情况下从你的 numpy git 仓库的根目录运行测试,这会导致奇怪的测试错误。
运行 linting#
可以在新添加的 Python 代码行上执行 lint 检查。
使用 pip 安装所有依赖包
$ python -m pip install -r requirements/linter_requirements.txt
要提交新代码之前运行 lint 检查,请运行
$ 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)
建议在将提交推送到远程分支之前运行 lint 检查,因为 linter 在 CI 管道中运行。
有关样式指南的更多详细信息
重建和清理工作区#
在对已编译代码进行更改后重建 NumPy 可以使用与之前相同的构建命令完成 - 仅重新构建已更改的文件。进行完整构建(有时是必要的)需要先清理工作区。标准方法如下(注意:删除所有未提交的文件!)
$ git clean -xdf
当你想要丢弃所有更改并返回到仓库中的最后一次提交时,请使用以下操作之一
$ git checkout .
$ git reset --hard
调试#
另一个经常被问到的问题是“我如何调试 NumPy 中的 C 代码?”。首先,确保你的系统上安装了 gdb 以及 Python 扩展(通常是 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 会自动设置 CFLAGS
和 CXXFLAGS
,它们默认情况下将包含 -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
文件。在这个文件中,你可以导出 CFLAGS
和 CXXFLAGS
变量。有关完整说明,请参阅 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
文件,并将 gdb 指向你的 Python 安装位置。例如,通过 pyenv 安装的 Python 版本需要一个具有以下内容的 .gdbinit
文件
add-auto-load-safe-path ~/.pyenv
强烈建议使用带有调试支持构建的 Python 构建 NumPy(在 Linux 发行版中通常打包为 python-dbg
)。
理解代码并入门#
更好地理解代码库的最佳策略是选择你想要更改的内容,然后开始阅读代码以了解它的工作原理。如有疑问,你可以在邮件列表中提问。如果你的拉取请求不完美,这完全没问题,社区始终乐于提供帮助。作为一个志愿者项目,有些事情确实会偶尔被遗漏,如果你发现某些事情在两到四周内都没有得到回复,那么联系我们完全没问题。
所以,赶快选择一些让你对 NumPy 感到恼火或困惑的事情,尝试代码,参与讨论,或者浏览参考文档,尝试修复它。事情会逐渐清晰,很快你就会对整个项目有一个相当好的了解。祝你好运!