Setup_requires с Cython?

Я создаю файл setup.py для проекта с некоторыми модулями расширения Cython.

Я уже получил это, чтобы работать:

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

setup(
    name=...,
    ...,
    ext_modules=cythonize([ ... ]),
)

Это устанавливает штраф. Однако это предполагает, что Cython установлен. Что делать, если он не установлен? Я понимаю, что это параметр setup_requires для:

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

setup(
    name=...,
    ...,
    setup_requires=['Cython'],
    ...,
    ext_modules=cythonize([ ... ]),
)

Однако, если Cython еще не установлен, это, конечно же, завершится неудачей:

$ python setup.py install
Traceback (most recent call last):
  File "setup.py", line 2, in <module>
    from Cython.Build import cythonize
ImportError: No module named Cython.Build

Каков правильный способ сделать это? Мне нужно как-то импортировать Cython только после выполнения шага setup_requires, но мне нужно Cython, чтобы указать значения ext_modules.

Ответ 1

Вы должны обернуть from Cython.Build import cythonize в try-except, а в except определить cythonize как фиктивную функцию. Таким образом, script может быть загружен без сбоев с помощью ImportError.

Затем, когда обрабатывается аргумент setup_requires, будет установлен Cython, и установка script будет выполнена повторно. Поскольку в этот момент Cython установлен, вы сможете успешно импортировать cythonize

try:
    from Cython.Build import cythonize
except ImportError:
     def cythonize(*args, **kwargs):
         from Cython.Build import cythonize
         return cythonize(*args, **kwargs)

ИЗМЕНИТЬ

Как отмечено в комментариях, после того, как setuptools имеет дело с отсутствующими зависимостями, он не перезагрузит Cython. Раньше я не думал об этом, но вы также можете попробовать использовать метод поздней привязки для создания cythonize

Ответ 2

Начиная с 18.0 выпуска setuptools (выпущенного в 2015-06-23), можно указать Cython в setup_requires и передать *.pyx модули для регулярных setuptools.Extension:

from setuptools import setup, Extension


setup(
    # ...
    setup_requires=[
        # Setuptools 18.0 properly handles Cython extensions.
        'setuptools>=18.0',
        'cython',
    ],
    ext_modules=[
        Extension(
            'mylib',
            sources=['src/mylib.pyx'],
        ),
    ],
)