测试 numpy.i 类型映射#
介绍#
numpy.i
为SWIG接口文件编写测试
是一件令人头痛的事情。目前,支持 12 种不同的数据类型,每种数据类型有 74 种不同的参数签名,总共支持“开箱即用”的 888 种类型映射。反过来,每个类型映射可能需要多次单元测试,以便验证正确和不正确输入的预期行为。目前,这会导致在子目录中运行时执行 1,000 多个单独的单元测试
。make test
numpy/tools/swig
为了促进许多类似的单元测试,采用了一些高级编程技术,包括 C 和SWIG宏以及 Python 继承。本文档的目的是描述用于验证numpy.i
类型映射是否按预期工作的测试基础设施。
测试组织#
支持三个独立的测试框架,分别针对一维、二维和三维数组。对于一维数组,有两个 C++ 文件,一个头文件和一个源文件,名称为:
Vector.h
Vector.cxx
包含各种以一维数组作为函数参数的函数的原型和代码。文件:
Vector.i
是一个SWIG接口文件,它定义了一个 python 模块Vector
,该模块包装了函数,Vector.h
同时利用类型映射来numpy.i
正确处理 C 数组。
调用生成和
,并且还执行编译扩展模块
或并将Makefile
其链接在一起的脚本,具体取决于平台。这个扩展模块和代理文件都放在该目录下的子目录中。swig
Vector.py
Vector_wrap.cxx
setup.py
Vector_wrap.cxx
_Vector.so
_Vector.dylib
Vector.py
build
实际测试使用名为以下的 Python 脚本进行:
testVector.py
它使用标准 Python 库模块unittest
,该模块对支持的每种数据类型定义的每个函数执行多项测试Vector.h
。
二维数组的测试方式完全相同。上述描述适用,但用Matrix
代替
Vector
。对于三维测试,替换Tensor
为
Vector
。对于四维测试,替换SuperTensor
为Vector
。对于平面就地阵列测试,请Flat
替换Vector
.对于下面的描述,我们将引用
Vector
测试,但相同的信息适用于Matrix
、
Tensor
和SuperTensor
测试。
该命令将确保构建所有测试软件,然后运行所有三个测试脚本。make test
测试头文件#
Vector.h
是一个 C++ 头文件,它定义了一个名为 的 C 宏,
TEST_FUNC_PROTOS
该宏带有两个参数:TYPE
,它是一个数据类型名称,例如; and ,它是相同数据类型的短名称,不带空格,例如。该宏定义了多个具有前缀的函数原型
,并且至少有一个参数为类型数组
。那些具有返回参数的函数会返回一个
值。unsigned int
SNAME
uint
SNAME
TYPE
TYPE
TEST_FUNC_PROTOS
然后针对以下支持的所有数据类型实现numpy.i
:
signed char
unsigned char
short
unsigned short
int
unsigned int
long
unsigned long
long long
unsigned long long
float
double
测试源文件#
Vector.cxx
是一个 C++ 源文件,它为 中指定的每个函数原型实现可编译代码Vector.h
。它定义了一个 C 宏,该宏具有与 中TEST_FUNCS
相同的参数和工作方式。
如上所述,对 12 种数据类型中的每一种进行了实现。TEST_FUNC_PROTOS
Vector.h
TEST_FUNCS
测试 SWIG 接口文件#
Vector.i
是一个定义 python 模块的
SWIGVector
接口文件。它遵循numpy.i
本章所述的使用约定。它定义了一个具有单个参数的SWIG宏
。它使用SWIG指令将提供的类型映射应用到 中找到的参数签名。然后针对 所支持的所有数据类型实现该宏
。然后,它使用 中的类型映射
来包装所有函数原型。%apply_numpy_typemaps
TYPE
%apply
Vector.h
numpy.i
%include "Vector.h"
Vector.h
numpy.i
测试 Python 脚本#
make
用于构建测试扩展模块
后,testVector.py
可以运行来执行测试。与用于unittest
促进单元测试的其他脚本一样,
testVector.py
定义一个继承自的类
unittest.TestCase
:
class VectorTestCase(unittest.TestCase):
然而,这个类并不是直接运行的。相反,它充当其他几个 Python 类的基类,每个类都特定于一种特定的数据类型。该类VectorTestCase
存储两个用于输入信息的字符串:
- self.typeStr
与 和
SNAME
中使用的前缀 之一匹配的字符串。例如,。Vector.h
Vector.cxx
"double"
- 自我类型代码
一个短(通常是单字符)字符串,表示 numpy 中的数据类型并对应于
self.typeStr
.例如,如果self.typeStr
是"double"
,那么self.typeCode
应该是"d"
。
类定义的每个测试都会VectorTestCase
通过访问模块的字典来提取它尝试测试的 python 函数Vector
:
length = Vector.__dict__[self.typeStr + "Length"]
在双精度测试的情况下,这将返回 python function Vector.doubleLength
。
然后,我们为每个支持的数据类型定义一个新的测试用例类,并带有简短的定义,例如:
class doubleTestCase(VectorTestCase):
def __init__(self, methodName="runTest"):
VectorTestCase.__init__(self, methodName)
self.typeStr = "double"
self.typeCode = "d"
这 12 个类中的每一个都被收集到一个 中unittest.TestSuite
,然后执行。错误和失败会汇总在一起并作为退出参数返回。任何非零结果都表明至少有一项测试未通过。