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

使用虚拟环境#

一个经常被问到的问题是"如何在与我用来完成工作/研究的已发布版本并行设置 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 ),然后创建您的 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

这会先构建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 来 match test names using python operators

$ 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 的所有测试都应该通过.

备注

测试套件中的某些测试需要大量内存,如果您的系统没有足够的内存,则会被跳过.

其他构建选项#

有关更多选项,包括选择编译器,设置自定义编译器标志和控制并行性,请参见 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 仓库的根目录运行测试,这将导致奇怪的测试错误.

运行linting#

可以对新添加的 Python 代码行执行 Lint 检查.

使用 pip 安装所有依赖包:

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

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

$ 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)

建议在将提交推送到远程分支之前运行 lint 检查,因为 linter 作为 CI 管道的一部分运行.

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

重新构建和清理工作区#

在更改已编译的代码后重新构建 NumPy 可以使用与之前使用的相同的构建命令来完成 - 只有更改的文件会被重新构建. 进行完整的构建,有时是必要的,需要首先清理工作区. 这样做的标准方法是(注意:删除任何未提交的文件!):

$ git clean -xdf

当您想要放弃所有更改并返回到 repo 中的最后一次提交时,请使用以下方法之一:

$ 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 会自动设置 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 文件,将 gdb 指向 Python 安装的位置.例如,通过 pyenv 安装的 python 版本需要一个包含以下内容的 .gdbinit 文件:

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

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

理解代码 & 开始#

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

所以,继续选择一些让你对 NumPy 感到恼火或困惑的东西,试验代码,参与讨论,或者浏览参考文档来尝试修复它.事情会慢慢好起来,很快你就会对整个项目有一个很好的理解.祝你好运!