获取Gitlab';s的持续集成,以编译用C编写的Python扩展 上下文

获取Gitlab';s的持续集成,以编译用C编写的Python扩展 上下文,python,gitlab,setuptools,gitlab-ci,python-unittest,Python,Gitlab,Setuptools,Gitlab Ci,Python Unittest,我有一个Python项目,我为它包装了一些C/C++代码(使用优秀的库)。我有一组C和Python单元测试,并且配置了Gitlab的CI在每次推送时运行它们。 C测试使用一个名为的最小单元测试框架,我使用Python的单元测试套件 在运行C测试之前,将编译并测试所有C代码。在运行Python测试之前,我还想编译Python的C/C++包装器,但是很难做到这一点 用几句话提问 在运行单元测试之前,是否有一种标准/好的方法让Gitlab CI使用setuptools构建Python扩展 用更多的词/

我有一个Python项目,我为它包装了一些C/C++代码(使用优秀的库)。我有一组C和Python单元测试,并且配置了Gitlab的CI在每次推送时运行它们。 C测试使用一个名为的最小单元测试框架,我使用Python的单元测试套件

在运行C测试之前,将编译并测试所有C代码。在运行Python测试之前,我还想编译Python的C/C++包装器,但是很难做到这一点

用几句话提问 在运行单元测试之前,是否有一种标准/好的方法让
Gitlab CI
使用
setuptools
构建Python扩展

用更多的词/描述我尝试的问题 为了在本地编译C/C++包装器,我使用
setuptools
setup.py
文件,其中包括
build\u ext
命令。 我使用
python setup.py build\u ext--inplace
本地编译所有内容(最后一个参数
--inplace
只会将编译后的文件复制到当前目录)。 据我所知,这是相当标准的

我在Gitlab上尝试做的是使用Python脚本(下面的代码),它将使用
os.system
命令运行一些命令(这似乎是一个糟糕的做法…)。 第一个命令是运行脚本构建并运行所有C测试。这是可行的,但我很乐意接受建议(我是否应该将Gitlab CI配置为单独运行C测试?)

现在,当我尝试使用
os.system(“cd python/\npython setup.py build\u ext--inplace”)
构建C/C++包装器时,问题来了。这会产生错误

File "setup.py", line 1, in <module>
        from setuptools import setup, Extension
    ImportError: No module named setuptools
但是,由于不是gitlab服务器上的sudo,我得到了以下错误
E:无法打开锁文件/var/lib/dpkg/lock-open(13:权限被拒绝)
。 有人知道解决这个问题的方法,或者更好的方法来解决这个问题吗

欢迎任何帮助

运行_tests.py文件
我的建议是将整个测试运行逻辑移到安装脚本中

使用
test
命令 首先,
setuptools
提供了一个
test
命令,因此您可以通过
python setup.py test
运行测试。更好的是,
test
在引擎盖下调用
build\u ext
命令,并将生成的扩展放置在测试中,这样就不需要显式调用
python setup.py build\u ext

$python setup.py测试
运行试验
运行蛋_信息
创建so.egg-info
正在编写so.egg-info/PKG-info
正在将dependency_链接写入so.egg-info/dependency_links.txt
将顶级名称写入so.egg-info/top_level.txt
正在编写清单文件“so.egg info/SOURCES.txt”
正在读取清单文件“so.egg info/SOURCES.txt”
正在编写清单文件“so.egg info/SOURCES.txt”
运行build_ext
构建“包裹纤维”扩展
创建构建
创建build/temp.linux-aarch64-3.6
AARC64未知linux gnu gcc-pthread-fPIC-I/data/gentoo64/usr/include/python3.6m-c wrap_fib.c-o build/temp.linux-AARC64-3.6/wrap_fib.o
aarch64未知linux gnu gcc-pthread-fPIC-I/data/gentoo64/usr/include/python3.6m-c cfib.c-o build/temp.linux-aarch64-3.6/cfib.o
创建build/lib.linux-aarch64-3.6
aarch64未知linux gnu gcc-pthread-shared-Wl,-O1-Wl,--根据需要-L.build/temp.linux-aarch64-3.6/wrap_fib.o build/temp.linux-aarch64-3.6/cfib.o-L/data/gentoo64/usr/lib64-lpython3.6m-o build/lib.linux-aarch64-3.6/wrap_fib.cpython-36m-aarch64-linux-gnu.so
正在复制build/lib.linux-aarch64-3.6/wrap_fib.cpython-36m-aarch64-linux-gnu.so->
测试fib\u 0(测试fib.fib测试)。。。好啊
测试纤维1(测试纤维纤维测试)。。。好啊
测试纤维10(测试纤维纤维测试)。。。好啊
----------------------------------------------------------------------
在0.002s内运行了3次测试
好啊
(我使用了中的代码进行处理,但输出应该与PyBind生成的非常类似)

使用额外的关键字 另一个方便的功能是额外的关键字
setuptools
添加:
test\u suite
tests\u require
test\u loader
()。下面是一个嵌入自定义测试套件的示例,正如您在
run\u tests.py
中所做的那样:

# setup.py

import unittest
from Cython.Build import cythonize
from setuptools import setup, Extension

exts = cythonize([Extension("wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])])


def pysuite():
    return unittest.TestLoader().discover('tests/python_tests')


if __name__ == '__main__':
    setup(
        name='so',
        version='0.1',
        ext_modules=exts,
        test_suite='setup.pysuite'
    )
扩展
test
命令 最后一个要求是运行C测试。我们可以通过重写
test
命令并从那里调用一些自定义代码来嵌入它们。这样做的好处是
distutils
提供了一个命令API,其中包含许多有用的功能,如复制文件或执行外部命令:

# setup.py

import os
import unittest
from Cython.Build import cythonize
from setuptools import setup, Extension
from setuptools.command.test import test as test_orig


exts = cythonize([Extension("wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])])


class test(test_orig):

    def run(self):
        # run python tests
        super().run()
        # run c tests
        self.announce('Running C tests ...')
        pwd = os.getcwd()
        os.chdir('tests/C_tests')
        self.spawn(['bash', 'run_all.sh'])
        os.chdir(pwd)

def pysuite():
    return unittest.TestLoader().discover('tests/python_tests')


if __name__ == '__main__':
    setup(
        name='so',
        version='0.1',
        ext_modules=exts,
        test_suite='setup.pysuite',
        cmdclass={'test': test}
    )
我扩展了原始的
test
命令,在python单元测试完成后运行一些额外的东西(注意通过
self.spawn
调用外部命令)。剩下的就是通过在设置函数中传递
cmdclass
将默认的
test
命令替换为自定义命令

现在,您已经在安装脚本中收集了所有内容,
python setup.py test
将完成所有脏工作

但是,由于不是gitlab服务器上的sudo,我得到了以下错误

我对Gitlab CI没有任何经验,但我无法想象在构建服务器上不可能安装软件包。也许这个问题会有帮助:

如果真的没有其他选择,你可以。但是,请注意,尽管此方法仍然有效

此外,如果您碰巧使用了最新版本的Python(3.4及更新版本),那么您应该将
pip
与Python发行版捆绑在一起,这样就可以在没有root权限的情况下安装
setuptools

$ python -m pip install --user setuptools

非常感谢你的回答!但是,我的测试与包装器不在同一目录中,并且命令
python setup.py test
找不到任何测试,我想这很容易解决。问题在于,此解决方案仍然假设能够加载
setuptools# setup.py

import os
import unittest
from Cython.Build import cythonize
from setuptools import setup, Extension
from setuptools.command.test import test as test_orig


exts = cythonize([Extension("wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])])


class test(test_orig):

    def run(self):
        # run python tests
        super().run()
        # run c tests
        self.announce('Running C tests ...')
        pwd = os.getcwd()
        os.chdir('tests/C_tests')
        self.spawn(['bash', 'run_all.sh'])
        os.chdir(pwd)

def pysuite():
    return unittest.TestLoader().discover('tests/python_tests')


if __name__ == '__main__':
    setup(
        name='so',
        version='0.1',
        ext_modules=exts,
        test_suite='setup.pysuite',
        cmdclass={'test': test}
    )
$ python -m pip install --user setuptools