如何在Cython中测试函数cdef' d?

时间:2017-02-15 20:48:27

标签: python unit-testing cython

我有一个.pyx文件,我在其中定义了一些函数,例如

cdef double foo(double a) nogil:
    return 3. * a

我如何在pyx文件之外对这些函数的行为进行单元测试?由于它们是cdef,我无法简单地导入它们......

2 个答案:

答案 0 :(得分:10)

要测试cdef功能,您需要用Cython编写测试。可以尝试使用cpdef函数,但是在这种情况下,并非所有签名都可以使用(例如,使用诸如int *float *之类的指针的签名)。

要访问cdef功能,您需要通过pxd文件“导出”它们:

#my_module.pyx:
cdef double foo(double a) nogil:
    return 3. * a

#my_module.pxd:
cdef double foo(double a) nogil

现在可以在Cython测试器中导入并测试功能:

#test_my_module.pyx
cimport my_module

def test_foo():
    assert my_module.foo(2.0)==6.0
    print("test ok")

test_foo()

现在

>>> cythonize -i my_module.pyx
>>> cythonize -i test_my_module.pyx 
>>> python -c "import test_my_module"
test ok

从那里去哪里取决于您的测试基础结构。


例如,如果您使用unittest-module,则可以使用pyximport cythonize /加载测试模块,检查它并将所有测试用例转换为unittest-test用例或使用{{1 }}直接在您的cython代码中(可能是更好的解决方案)。

这是unittest的概念证明:

unittest

现在我们只需要翻译和导入纯python即可#test_my_module.pyx cimport my_module import unittest class CytTester(unittest.TestCase): def test_foo(self): self.assertEqual(my_module.foo(2.0),6.0)

unittest

现在:

#test_cy.py 
import pyximport; pyximport.install()
from test_my_module import *

import unittest

顺便说一句,不需要显式地对pyx模块进行cythonize->>> python -m unittest test_cy.py . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK 自动为我们完成。

警告提示:pyximport会在pyximport(或其他操作系统中类似)中缓存经过cythonized处理的c文件,只要~/.pyxbld不变该扩展程序不会重建。当test_my_module.pyx更改并导致二进制不兼容时,可能会出现问题(幸运的是,如果出现这种情况,python会发出警告)。

必须在测试环境中确保重建pyx文件(基于时间戳)或删除缓存文件(可以使用临时目录,例如使用{{ 3}},通过tempfile.TemporaryDirectory())。


如果您使用虚拟环境并通过my_module(或类似的工作流程)安装cython软件包,则需要pyximport.install(build_dir=...),即您的安装文件需要添加:

setup.py

答案 1 :(得分:0)

尽管前面提到过,最简单的方法是更改​​ cpdefcdef 声明:

cpdef double foo(double a) nogil:
    return 3. * a

无需更改任何其他内容。对于大多数用途,它们实际上是相同的,cpdef 的开销略高,但在继承方面表现更好,请参阅 details here

<块引用>

指令 cpdef 使该方法的两个版本可用;一 在 Cython 中使用速度快,在 Python 中使用速度慢。然后:

这比为 cdef 提供一个 python 包装器做的稍微多一点 方法:与 cdef 方法不同,cpdef 方法可以完全覆盖 Python 子类中的方法和实例属性。它增加了一点 与 cdef 方法相比的调用开销。