设置和使用您的开发环境#
推荐的开发设置#
由于 NumPy 包含需要在使用前编译的 C 和 Cython 部分,请确保已安装必要的编译器和 Python 开发头文件 - 请参阅 从源代码构建.从版本 2.0
开始,构建 NumPy 需要符合 C11 和 C++17 的编译器.
编译代码还意味着从开发源导入 NumPy 需要一些额外的步骤,这些步骤如下所述.在本章的其余部分,我们假设您已按照 使用 git 中所述设置了您的 git 仓库.
备注
如果你在从源代码构建 NumPy 或设置本地开发环境时遇到问题,你可以尝试使用 GitHub Codespaces 来构建 NumPy.它允许你在浏览器中直接创建正确的开发环境,减少安装本地开发环境和处理不兼容依赖项的需求.
如果你有良好的互联网连接并且想要一个临时的设置,在 Codespaces 环境中工作通常会更快.有关如何开始使用 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
如果你通过其他方式安装了Python而不是conda,首先安装 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 的开发版本并运行测试,生成带有正确设置 Python 导入路径等的交互式 shell,请使用 spin 工具.要运行测试,请执行以下任一操作:
$ 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 旋转命令.它依赖于 scipy-docs 包,该包在标准库 doctest
包的基础上提供了几个附加功能.安装 scipy-doctest
并运行以下之一:
$ spin check-docs -v
$ spin check-docs numpy/linalg
$ spin check-docs -v -- -k 'det and not slogdet'
备注
请记住,在提交更改之前,所有 NumPy 的测试都应该通过.
备注
测试套件中的一些测试需要大量的内存,如果您的系统没有足够的内存,这些测试将被跳过.
其他构建选项#
有关更多选项,包括选择编译器、设置自定义编译器标志和控制并行性,请参见 Compiler selection and customizing a build (来自 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代码行执行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 代码?”.首先,确保你的系统上安装了带有 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://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#saving-environment-variables.
接下来,您需要编写一个调用您想要调试的C代码的Python脚本.例如 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-gdb.py
脚本随Python一起分发,并安装在gdb可以找到的路径中.如果你通过系统包管理器安装了Python构建,你可能不需要手动做任何事情.然而,如果你从源代码构建了Python,你可能需要在你的主目录中创建一个 .gdbinit
文件,指向你的Python安装位置.例如,通过 pyenv 安装的Python版本需要一个包含以下内容的 .gdbinit
文件:
add-auto-load-safe-path ~/.pyenv
强烈建议使用带有调试支持的 Python 构建 NumPy(在 Linux 发行版中通常打包为 python-dbg
).
理解代码和入门#
要更好地理解代码库的最佳策略是选择一些你想改变的东西,并开始阅读代码以弄清楚它是如何工作的.如果有疑问,你可以在邮件列表中提问.如果你的拉取请求不完美,那也没关系,社区总是乐于提供帮助.作为一个志愿者项目,有时事情会被遗漏,如果某件事在没有回应的情况下已经放置了两到四周,完全可以提醒我们.
所以,继续选择一些让你烦恼或困惑的NumPy问题,尝试代码实验,参与讨论或查阅参考文档尝试解决它.事情会逐渐明朗,很快你将对整个项目有一个相当好的理解.祝你好运!