Получить непрерывную интеграцию Gitlab для компиляции расширения Python, написанного на C - PullRequest
0 голосов
/ 06 июня 2018

Context

У меня есть проект Python, для которого я обертываю некоторый код C / C ++ (используя отличную библиотеку PyBind ).У меня есть набор модульных тестов C и Python, и я настроил CI Gitlab для запуска их при каждом нажатии.В C-тестах используется минималистский фреймворк для модульных тестов, называемый minunit , а я использую пакет юнит-тестов Python.

Перед запуском C-тестов весь C-код компилируется и затем тестируется.Я также хотел бы скомпилировать оболочку C / C ++ для Python перед запуском тестов Python, но мне трудно это сделать.

Вопрос в нескольких словах

Есть ли стандарт?/ хороший способ получить Gitlab-CI для создания расширения Python с использованием setuptools перед запуском юнит-тестов?

Вопрос с большим количеством слов / Описание того, что я пробовал

Для компиляции C /Оболочка C ++ локально, я использую setuptools с файлом setup.py, включая команду build_ext.Я локально компилирую все с помощью python setup.py build_ext --inplace (последний аргумент --inplace просто скопирует скомпилированный файл в текущий каталог).Насколько я знаю, это вполне стандартно.

То, что я пытался сделать на Gitlab, это иметь скрипт Python (код ниже), который будет запускать несколько команд с помощью команды os.system (которая выглядит какплохая практика ...).Первая команда - запустить сборку скрипта и запустить все тесты на Си.Это работает, но я рад принять рекомендации (я должен настроить 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

Поэтому я попытался изменить файл конфигурации CI моего gitlab для установки python-dev.Мой .gitlab-ci.yml выглядит как

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

Но, не будучи sudo на сервере gitlab, я получаю следующую ошибку E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied).Кто-нибудь знает способ обойти это или лучший способ решить эту проблему?

Любая помощь будет более чем приветствоваться!

run_tests.py file

    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)

1 Ответ

0 голосов
/ 06 июня 2018

Я бы предложил перенести всю логику выполнения теста в сценарий установки.

с использованием test команды

Прежде всего, setuptools отправляет команду test, поэтомуВы можете запустить тесты через python setup.py test.Более того, test вызывает команду build_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_suite, tests_require, test_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 сделает всю грязнуюjob.

Но, не будучи sudo на сервере gitlab, я получаю следующую ошибку

У меня нет опыта работы с Gitlab CI, но я могу 'Представьте, что нет возможности установить пакеты на сервере сборки.Может быть, этот вопрос будет полезен: Как использовать sudo в скрипте сборки для gitlab ci?

Если другого варианта нет, вы можете загрузить локальную копию setuptools с ez_setup.py.Однако обратите внимание, что хотя этот метод все еще работает, недавно он был объявлен устаревшим .

Кроме того, если вам случится использовать последнюю версию Python (3.4 и новее), то вам следует иметьpip в комплекте с дистрибутивом Python, поэтому должна быть возможность установить setuptools без прав root с

$ python -m pip install --user setuptools
...