获取Gitlab的持续集成,以编译用C编写的Python扩展

基督教

语境

我有一个Python项目,为此我包装了一些C / C ++代码(使用出色的PyBind库)。我有一组C和Python单元测试,并且已配置Gitlab的CI以在每次推送时运行它们。C测试使用称为minunit的极简单元测试框架,而我使用Python的unittest套件。

在运行C测试之前,将编译所有C代码,然后进行测试。我还想在运行Python测试之前为Python编译C / C ++包装器,但这样做很难。

几个问题

在运行单元测试之前,是否有标准/好的方法来Gitlab-CI构建Python扩展setuptools

问题更多单词/我尝试过的描述

为了在本地编译C / C ++包装器,我使用setuptoolssetup.py包含build_ext命令文件我在本地编译所有内容python setup.py build_ext --inplace(最后一个arg--inplace只会将编译后的文件复制到当前目录中)。据我所知,这是很标准的。

我试图在Gitlab上做的是拥有一个Python脚本(下面的代码),该脚本将使用os.systemcommand运行一些命令(这似乎是一种不好的做法...)。第一个命令是运行脚本构建并运行所有C测试。这可行,但是我很乐意提出建议(我应该配置Gitlab CI来单独运行C测试吗?)。

现在,问题出在我尝试使用构建C / C ++包装器时os.system("cd python/ \npython setup.py build_ext --inplace")这会产生错误

File "setup.py", line 1, in <module>
        from setuptools import setup, Extension
    ImportError: No module named setuptools

因此,我尝试修改gitlab的CI配置文件以安装python-dev。我的.gitlab-ci.yml样子

test:
  script:
  - apt-get install -y python-dev
  - python run_tests.py

但是,不是在gitlab的服务器上使用sudo,我得到了以下错误E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)有谁知道解决这个问题的方法,还是解决这个问题的更好方法?

任何帮助都将非常受欢迎!

run_tests.py文件

    import unittest
    import os
    from shutil import copyfile
    import glob


    class AllTests(unittest.TestCase):
        def test_all(self):
            # this automatically loads all tests in current dir
            testsuite = unittest.TestLoader().discover('tests/Python_tests')
            # run tests
            result = unittest.TextTestRunner(verbosity=2).run(testsuite)
            # send/print results
            self.assertEqual(result.failures, [], 'Failure')


    if __name__ == "__main__":
        # run C tests
        print(' ------------------------------------------------------ C TESTS')
        os.system("cd tests/C_tests/ \nbash run_all.sh")

        # now python tests
        print(' ------------------------------------------------- PYTHON TESTS')
        # first build and copy shared library compiled from C++ in the python test directory
        # build lib 
        os.system("cd python/ \npython setup.py build_ext --inplace")
        # copy lib it to right place
        dest_dir = 'tests/Python_tests/'
        for file in glob.glob(r'python/*.so'):
            print('Copying file to test dir : ', file)
            copyfile(file, dest_dir+file.replace('python/', ''))
        # run Python tests
        unittest.main(verbosity=0)
马蹄铁

我的建议是将整个测试运行逻辑移到设置脚本中。

使用test命令

首先,setuptools附带一个test命令,因此您可以通过来运行测试python setup.py test更好的是,testcallsbuild_ext命令在后台进行,并放置已构建的扩展,以便在测试中可以访问它们,因此您无需python setup.py build_ext显式调用

$ python setup.py test
running test
running egg_info
creating so.egg-info
writing so.egg-info/PKG-INFO
writing dependency_links to so.egg-info/dependency_links.txt
writing top-level names to so.egg-info/top_level.txt
writing manifest file 'so.egg-info/SOURCES.txt'
reading manifest file 'so.egg-info/SOURCES.txt'
writing manifest file 'so.egg-info/SOURCES.txt'
running build_ext
building 'wrap_fib' extension
creating build
creating build/temp.linux-aarch64-3.6
aarch64-unknown-linux-gnu-gcc -pthread -fPIC -I/data/gentoo64/usr/include/python3.6m -c wrap_fib.c -o build/temp.linux-aarch64-3.6/wrap_fib.o
aarch64-unknown-linux-gnu-gcc -pthread -fPIC -I/data/gentoo64/usr/include/python3.6m -c cfib.c -o build/temp.linux-aarch64-3.6/cfib.o
creating build/lib.linux-aarch64-3.6
aarch64-unknown-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,--as-needed -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
copying build/lib.linux-aarch64-3.6/wrap_fib.cpython-36m-aarch64-linux-gnu.so ->
test_fib_0 (test_fib.FibonacciTests) ... ok
test_fib_1 (test_fib.FibonacciTests) ... ok
test_fib_10 (test_fib.FibonacciTests) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK

(我使用了Cython Book示例存储库中的代码,但是输出应该与PyBind产生的输出非常相似)。

使用额外的关键字

这可能会派上用场是多余的关键字另一个特点setuptools补充说:test_suitetests_requiretest_loader文档)。这是一个嵌入自定义测试套件的示例,就像您在中所做的那样run_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)。剩下的就是test通过传入cmdclass设置功能用自定义命令替换默认命令

现在,您已在设置脚本中收集了所有内容,python setup.py test并将完成所有肮脏的工作。

但是,不是在gitlab的服务器上使用sudo,我收到以下错误

我没有使用Gitlab CI的经验,但是我无法想象不可能在构建服务器上安装软件包。也许这个问题会有所帮助:如何在gitlab ci的构建脚本中使用sudo?

如果真的有没有其他选择,你可以引导的本地副本setuptoolsez_setup.py但是请注意,尽管此方法仍然有效,但最近已弃用

另外,如果您恰巧使用的是Python的最新版本(3.4及更高版本),则应pip将其与Python发行版捆绑在一起,因此应该可以在setuptools没有root权限的情况下进行安装

$ python -m pip install --user setuptools

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章