诗歌+ Cython +测验(Nosetests)

问题描述 投票:1回答:1

我使用Poetry来构建带有cython扩展名的软件包。现在,我想为此编写测试(最好使用鼻子测试)。问题是我需要预编译二进制文件,通常使用setup.py build_clib build_ext --inplace

对我来说,最好的解决方案是运行测试,而无需在目录中创建额外的.py.sh文件,因为我已经拥有build.py。可以在虚拟环境中安装该软件包后再运行测试,就像在readthedocs服务器上实现的一样。

我也很熟悉taskipy,所以我pyproject.toml中的一些bash命令也可以。欢迎使用任何其他与pyproject.toml兼容的软件包。

[也许有任何诗意的钩子,因为它在创建.whl分发文件时会进行声囊化和编译。

对此将提供任何帮助。

UPD Tox看起来像是合适的工具,但在目录中却看不到pyproject.toml。非常欢迎使用软件包或教程中的tox和cython链接到回购协议。

python python-3.x cython nose python-poetry
1个回答
1
投票

如果扩展名是发行版的一部分,除了运行poetry install之外,您无需执行任何其他操作-poetry将就地构建扩展名,作为项目可编辑安装的一部分。

[在其他情况下,您可以在套件设置/拆卸过程中将调用distutils命令嵌入到测试中。我对nose不太熟悉,但这是一个简单的示例。想象一下,我有一个fib.pyx(这是Cython书中的一个示例):

def fib(long n):
    '''Returns the nth Fibonacci number.'''
    cdef long a=0, b=1, i
    for i in range(n):
        a, b = a + b, a
    return a

一个构建test_fib.py库并在测试成功时将其删除的fib模块:

from distutils.dist import Distribution
from distutils.core import Extension
from pathlib import Path
from Cython.Build import cythonize


fib_source = Path('fib.pyx')

# distutils magic. This is essentially the same as calling
# python setup.py build_ext --inplace
dist = Distribution(attrs={'ext_modules': cythonize(fib_source.name)})
build_ext_cmd = dist.get_command_obj('build_ext')
build_ext_cmd.ensure_finalized()
build_ext_cmd.inplace = 1
build_ext_cmd.run()

fib_obj = Path(build_ext_cmd.get_ext_fullpath(fib_source.stem))

# the lib was built, so the import will succeed now
from fib import fib


def teardown_module():
    # remove built library
    fib_obj.unlink()

    # if you also want to clean the build dir:
    from distutils.dir_util import remove_tree
    remove_tree(build_ext_cmd.build_lib)
    remove_tree(build_ext_cmd.build_temp)


# sample tests

def test_zero():
    assert fib(0) == 0


def test_ten():
    assert fib(10) == 55

您可能正在自定义setup_kwargs中自定义build.py。要重用此代码,请修改dist初始化,例如:

from build import build

setup_kwargs = {}
build(setup_kwargs)
dist = Distribution(attrs=setup_kwargs)
...

pytest示例

pytest可以更方便地组织事物。创建一个名为conftest.py的文件,并将安装/拆卸代码提取到钩子中:

# conftest.py

from distutils.core import Extension
from distutils.dist import Distribution
from distutils.dir_util import remove_tree
from pathlib import Path
from Cython.Build import cythonize


def pytest_sessionstart(session):
    fib_source = Path('fib.pyx')
    dist = Distribution(attrs={'ext_modules': cythonize(fib_source.name)})
    build_ext_cmd = dist.get_command_obj('build_ext')
    build_ext_cmd.ensure_finalized()
    build_ext_cmd.inplace = 1
    build_ext_cmd.run()
    session.fib_obj = Path(build_ext_cmd.get_ext_fullpath(fib_source.stem))


def pytest_sessionfinish(session):
    session.fib_obj.unlink()

现在,测试变得更加整洁,并且在整个测试会话中只需运行一次设置代码。上面的测试示例,重新访问:

from fib import fib


def test_zero():
    assert fib(0) == 0


def test_ten():
    assert fib(10) == 55
© www.soinside.com 2019 - 2024. All rights reserved.