设置和使用您的开发环境#
推荐的开发设置#
由于 NumPy 包含部分用 C 和 Cython 编写的代码,在使用前需要进行编译,请确保您已安装必要的编译器和 Python 开发头文件 - 请参阅 从源码构建。从 NumPy 版本 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 的开发版本?”
实现这一目标的一个简单方法是,例如使用 pip 或 conda 将已发布版本安装到 site-packages 中,然后在虚拟环境中设置开发版本。
如果您使用 conda,我们建议使用仓库根目录中的 environment.yml 文件为 NumPy 开发创建一个单独的虚拟环境(这将一次性创建环境并安装所有开发依赖项)
$ conda env create -f environment.yml # `mamba` works too for this command
$ conda activate numpy-dev
如果您通过 conda 以外的其他方式安装了 Python,请首先安装 virtualenv(可选地使用 virtualenvwrapper),然后创建您的 virtualenv(此处命名为 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 工具启动交互式 shell,并正确设置 Python 导入路径等。要运行测试,请执行以下任一命令:
$ 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
$ spin test -p auto # to run tests in parallel threads using pytest-run-parallel
这将首先构建 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 运行测试。例如,要构建 NumPy 并使用 Python 3.9 运行测试套件,请执行:
$ tox -e py39
有关更全面的信息,请参阅 测试指南。
注意:不要在您的 numpy git 仓库的根目录下运行测试,除非使用 spin,否则会导致奇怪的测试错误。
运行类型检查#
涉及静态类型声明的更改也使用 spin 执行。调用将如下所示:
$ spin mypy
这将在 typing/tests 目录中查找用于测试类型不兼容性的操作集。
运行代码风格检查#
可以对新添加的 Python 代码行执行代码风格检查。
使用 pip 安装所有依赖包
$ python -m pip install -r requirements/linter_requirements.txt
在提交新代码之前运行代码风格检查,请执行:
$ python tools/linter.py
要检查当前分支中新添加的 Python 代码与目标分支的所有更改,请执行:
$ python tools/linter.py
如果没有错误,脚本将退出,不显示任何消息。如果出现错误,请检查错误消息以获取详细信息。
$ python tools/linter.py
./numpy/_core/tests/test_scalarmath.py:34:5: E303 too many blank lines (3)
1 E303 too many blank lines (3)
建议在将提交推送到远程分支之前运行代码风格检查,因为 linter 会在 CI 管道中运行。
有关风格指南的更多详细信息
重新构建和清理工作区#
更改编译后的代码后重新构建 NumPy 可以使用您之前使用的相同的构建命令——只有更改的文件才会被重新构建。执行完全构建(有时是必要的)需要先清理工作区。标准的做法是(*注意:会删除任何未提交的文件!*):
$ git clean -xdf
当您想丢弃所有更改并返回到仓库中的上一个提交时,可以使用以下任一命令:
$ 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 会自动设置 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://docs.conda.org.cn/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 构建(在 Linux 发行版上通常打包为 python-dbg)来构建 NumPy。
理解代码与入门#
更好地理解代码库的最佳策略是选择您想修改的内容,然后开始阅读代码以找出其工作原理。如有疑问,可以在邮件列表中提问。您的 pull request 不完美也没关系,社区总是乐于助人。作为一个志愿者项目,有时事情可能会被搁置,如果某个请求在两到四周内没有得到响应,您可以随时提醒我们。
所以,尽管去选择那些让您对 NumPy 感到恼火或困惑的地方,尝试修改代码,参与讨论,或者查阅参考文档来尝试修复它。事情会逐渐明朗,您很快就会对整个项目有相当好的理解。祝您好运!