构建/测试带C扩展的Python项目
我有一个项目,里面有一个Python包和一个编译好的组件。现在的目录结构是:
<project>
foo/
foo/__init__.py
foo/...
src/
src/c_foo.c
tests/
tests/test_foo.py
setup.py
当项目构建时,distutils会创建一个build/lib
目录,我要么把它添加到PYTHONPATH
中,要么安装到一个虚拟环境里。最终的结构如下:
<project>
build/lib
build/lib/foo/__init__.py
build/lib/foo/c_foo.so
问题是,如果我从项目根目录启动Python解释器,或者从项目根目录运行测试等,它会优先使用源代码树,而不是构建后的树。
我找到了一些现有的解决方案:
把Python源代码放在一个单独的目录下,比如
lib/foo
、modules/foo
等。这样做的缺点是,所有源文件都多了一个目录层级,而且与那些没有编译扩展的项目不一致,因为它们的Python包通常就在根目录下。把包放在根目录,这样就需要从项目根目录
chdir
到其他目录(比如进入tests/目录),这样Python解释器就看不到源代码包(可以通过构建脚本或手动操作)。把包放在根目录,但用不同的名字(比如
foo-module
或foo-lib
),并在setup.py
中加上package_dir={'foo':'lib-foo'}
这一行。这是第一种方法的变体,没有额外的目录层级,我想这基本上是一样的。把包放在根目录,并使用
setup.py build_ext --inplace
,但这样会污染源代码树。
无论哪种情况,相比于一个普通的Python项目,这些方法都增加了额外的复杂性,因为在普通项目中可以直接从源代码树修改或运行代码。我很想听听大家对上述方法的优缺点的看法,以及你们在项目中使用的具体方法。
1 个回答
你可以试试在 distribute(以前叫setuptools) 中使用 develop
这个目标。
确保你已经安装了 distribute
,然后像下面这样修改你的 setup.py
文件:
# the setuptools package name is still used
from setuptools import setup, Extension
...
接着进入你的虚拟环境,运行 develop
:
% source ~/virt/bin/activate
(virt)% cd ~/project
(virt)% python setup.py develop
这样你就可以在项目的根目录下运行测试了,而且每次你激活这个虚拟环境时,都可以访问这个项目的包和扩展,无论你的路径是什么:
% cd /tmp
% source ~/virt/bin/activate
(virt)% python -c 'import foo, c_foo; print foo, c_foo'
<module 'foo' from '/Users/user/project/foo/__init__.py'>
<module 'c_foo' from '/Users/user/project/c_foo.so'>