诗歌 + Cython + 测试(Nosetests)
Poetry + Cython + tests (Nosetests)
我使用 Poetry 构建带有 cython 扩展的包。现在我想为它编写测试(最好使用 nosetest)。问题是我需要预编译二进制文件,通常使用 setup.py build_clib build_ext --inplace
对我来说最好的解决方案是 运行 测试而不在目录中创建额外的 .py
或 .sh
文件,因为我已经有 build.py
。在虚拟环境中安装包后运行测试就可以了,就像在readthedocs服务器上实现的一样。
我也熟悉了taskipy
,所以我的pyproject.toml
中的一些bash命令也可以。欢迎使用 pyproject.toml
的任何其他软件包。
也许 Poetry 有任何钩子,因为它在创建 .whl
分发文件时进行了 cythonizes 和 comiles。
如有任何帮助,我们将不胜感激。
UPD Tox 看起来是合适的工具,但它在目录中时看不到 pyproject.toml
。非常欢迎在包或教程中使用 tox 和 cython 的 repos 链接。
如果扩展是分发的一部分,除了 运行ning poetry install
- poetry
将就地构建扩展作为项目的可编辑安装。
在其他情况下,您可以在测试中嵌入调用 distutils
命令作为套件 setup/teardown 的一部分。我对 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
您可能正在自定义 build.py
中的 setup_kwargs
。要重用此代码,请调整 dist
初始化,例如:
from build import build
setup_kwargs = {}
build(setup_kwargs)
dist = Distribution(attrs=setup_kwargs)
...
pytest
例子
使用 pytest
可以更方便地组织事情。使用提取到挂钩的 setup/teardown 代码创建一个名为 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
以下是对已接受的答案(pytest 示例)的轻微改动,现在在将 src 代码和测试代码分开在不同目录中时也可以使用。
例如
.
|_ src/
|_ your_package/
|_ some_cython_module.pyx
|_ test/
|_ conftest.py
|_ some_cython_module_test.py
# conftest.py
from distutils.dist import Distribution
from pathlib import Path
from Cython.Build import cythonize
def pytest_sessionstart(session):
difflib_source = Path('src/your_package/some_cython_module.pyx')
dist = Distribution(attrs={'ext_modules': cythonize(str(difflib_source))})
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(
str(difflib_source.parents[0]) + '/' + difflib_source.stem
))
def pytest_sessionfinish(session):
session.fib_obj.unlink()
我使用 Poetry 构建带有 cython 扩展的包。现在我想为它编写测试(最好使用 nosetest)。问题是我需要预编译二进制文件,通常使用 setup.py build_clib build_ext --inplace
对我来说最好的解决方案是 运行 测试而不在目录中创建额外的 .py
或 .sh
文件,因为我已经有 build.py
。在虚拟环境中安装包后运行测试就可以了,就像在readthedocs服务器上实现的一样。
我也熟悉了taskipy
,所以我的pyproject.toml
中的一些bash命令也可以。欢迎使用 pyproject.toml
的任何其他软件包。
也许 Poetry 有任何钩子,因为它在创建 .whl
分发文件时进行了 cythonizes 和 comiles。
如有任何帮助,我们将不胜感激。
UPD Tox 看起来是合适的工具,但它在目录中时看不到 pyproject.toml
。非常欢迎在包或教程中使用 tox 和 cython 的 repos 链接。
如果扩展是分发的一部分,除了 运行ning poetry install
- poetry
将就地构建扩展作为项目的可编辑安装。
在其他情况下,您可以在测试中嵌入调用 distutils
命令作为套件 setup/teardown 的一部分。我对 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
您可能正在自定义 build.py
中的 setup_kwargs
。要重用此代码,请调整 dist
初始化,例如:
from build import build
setup_kwargs = {}
build(setup_kwargs)
dist = Distribution(attrs=setup_kwargs)
...
pytest
例子
使用 pytest
可以更方便地组织事情。使用提取到挂钩的 setup/teardown 代码创建一个名为 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
以下是对已接受的答案(pytest 示例)的轻微改动,现在在将 src 代码和测试代码分开在不同目录中时也可以使用。
例如
.
|_ src/
|_ your_package/
|_ some_cython_module.pyx
|_ test/
|_ conftest.py
|_ some_cython_module_test.py
# conftest.py
from distutils.dist import Distribution
from pathlib import Path
from Cython.Build import cythonize
def pytest_sessionstart(session):
difflib_source = Path('src/your_package/some_cython_module.pyx')
dist = Distribution(attrs={'ext_modules': cythonize(str(difflib_source))})
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(
str(difflib_source.parents[0]) + '/' + difflib_source.stem
))
def pytest_sessionfinish(session):
session.fib_obj.unlink()