如何在使用Cython的Python3项目中结合pytest开展单元测试?
我之前在Cython项目里用pytest的时候也碰到过一模一样的麻烦——默认导不了Cython模块,试了pytest-cython也没用,还发现PyCharm根本不用我pip装的包。折腾了好一阵,总结出几个靠谱的解决办法:
首先要明确:pytest本身是可以导入Cython模块的,核心问题是你得先把Cython代码编译成Python能识别的扩展模块,并且让pytest能找到这个模块。
第一步:确保Cython模块正确编译
不管用什么工具,先把.pyx文件编译成可导入的二进制文件(Linux/macOS是.so,Windows是.pyd)。最常用的是用setup.py:from setuptools import setup from Cython.Build import cythonize setup( name="your_cython_project", ext_modules=cythonize("src/**/*.pyx", language_level="3"), )然后运行命令编译到当前目录:
python setup.py build_ext --inplace编译完成后,你会在
.pyx文件同目录下看到对应的二进制模块,这时候pytest就能像导入普通Python模块一样导入它了。如果编译后的模块不在默认路径,手动添加到sys.path
要是你把编译产物放到了单独的目录(比如build/lib),可以在项目根目录创建conftest.py,把编译目录加到Python路径里:import sys from pathlib import Path # 替换成你的编译产物实际路径 build_dir = Path(__file__).parent / "build" / "lib.linux-x86_64-3.10" sys.path.insert(0, str(build_dir))这样pytest运行时会自动加载这个路径下的模块。
别纠结pytest-cython了,它不是必须的
我当初也抱着试试的心态装了pytest-cython,结果发现它主要是用来做Cython的性能分析、类型检查这类进阶操作,普通的单元测试完全用不上它。只要你的Cython模块编译好了,普通pytest就能正常导入测试。
PyCharm有时候会默认用自带的包仓库或者自定义仓库,导致你用pip装的包(比如pytest、Cython)不被识别,解决起来也很简单:
切换到正确的Python解释器
打开File > Settings > Project: [你的项目名] > Python Interpreter,看看当前选中的解释器是不是你本地用pip装包的那个环境(比如虚拟环境、系统Python)。如果不是,点击右上角的齿轮图标,选择Add,找到你自己的环境并选中,这样PyCharm就会使用这个环境里的包了。把编译后的模块目录标记为Sources Root
找到你编译好的Cython模块所在的目录,右键点击它,选择Mark Directory as > Sources Root。这样PyCharm会把这个目录加到Python路径中,不仅代码里能自动补全,运行pytest时也能正确找到模块。手动同步缺失的包
如果切换解释器后还是有些包没识别到,可以在Python Interpreter设置里,点击+号,搜索你需要的包(比如pytest、Cython),然后安装到当前选中的解释器里,就能和pip装的包保持一致了。
内容的提问来源于stack exchange,提问作者PDiracDelta

