F2PY 测试套件#

F2PY 的测试套件存在于目录 numpy/f2py/tests 中.其目的是确保 Fortran 语言特性被正确地翻译成 Python.例如,用户可以在 Fortran 中指定数组的起始和结束索引.这种行为被转换到生成的 CPython 库中,其中数组严格地从 0 索引开始.

测试套件的目录如下所示:

./tests/
├── __init__.py
├── src
│   ├── abstract_interface
│   ├── array_from_pyobj
│   ├── // ... several test folders
│   └── string
├── test_abstract_interface.py
├── test_array_from_pyobj.py
├── // ... several test files
├── test_symbolic.py
└── util.py

test_ 开头的文件包含从解析 Fortran 文件到检查模块文档的 f2py 各个方面的测试. src 目录包含我们进行测试的 Fortran 源文件. util.py 包含用于在使用临时位置的测试期间构建和导入 Fortran 模块的实用函数.

添加测试#

F2PY 当前的测试套件早于 pytest ,因此不使用 fixtures.相反,测试文件包含从 util.py 中的 F2PyTest 类继承的测试类.

 1    backend = SimplifiedMesonBackend(
 2        modulename=module_name,
 3        sources=source_files,
 4        extra_objects=kwargs.get("extra_objects", []),
 5        build_dir=build_dir,
 6        include_dirs=kwargs.get("include_dirs", []),
 7        library_dirs=kwargs.get("library_dirs", []),
 8        libraries=kwargs.get("libraries", []),
 9        define_macros=kwargs.get("define_macros", []),
10        undef_macros=kwargs.get("undef_macros", []),

此类包含许多用于解析和编译测试源文件的辅助函数.它的子类可以覆盖它的 sources 数据成员以提供它们自己的源文件.然后,这个超类将在对象创建时编译添加的源文件,并且它们的函数将被附加到 self.module 数据成员.因此,子类将能够通过调用 self.module.[fortran_function_name] 访问源文件中指定的 fortran 函数.

在 v2.0.0b1 版本加入.

即使主机上没有 Fortran 编译器,也应确保每个 f2py 测试都能成功运行.为了简化此过程,使用了 CompilerChecker ,它本质上提供了一组 meson 依赖的实用程序,即 has_{c,f77,f90,fortran}_compiler() .

对于 test_f2py2e 中的 CLI 测试,预期会调用 meson 或者依赖编译器的标志,需要调用 compiler_check_f2pycli() ,而不是 f2pycli() .

示例#

考虑以下子程序,包含在一个名为 add-test.f 的文件中

        subroutine addb(k)
          real(8), intent(inout) :: k(:)
          k=k+1
        endsubroutine

        subroutine addc(w,k)
          real(8), intent(in) :: w(:)
          real(8), intent(out) :: k(size(w))
          k=w+1
        endsubroutine

第一个例程 addb 只是简单地获取一个数组,并将其元素增加 1.第二个子程序 addc 分配一个新的数组 k ,其元素比输入数组 w 的元素大 1.

一个测试可以实现如下:

class TestAdd(util.F2PyTest):
    sources = [util.getpath("add-test.f")]

    def test_module(self):
        k = np.array([1, 2, 3], dtype=np.float64)
        w = np.array([1, 2, 3], dtype=np.float64)
        self.module.addb(k)
        assert np.allclose(k, w + 1)
        self.module.addc([w, k])
        assert np.allclose(k, w + 1)

我们覆盖了 sources 数据成员以提供源文件.源文件被编译,并且当创建类对象时,子程序被附加到模块数据成员. test_module 函数调用子程序并测试它们的结果.