setup_requires только для некоторых команд

У меня есть пакет Python в стиле distutils, который требует определенной и довольно большой зависимости для этапа сборки. В настоящее время эта зависимость указана под setup_requires аргумент к distutils.setup. К сожалению, это означает, что зависимость будет построена для любого выполнения setup.py, в том числе при запуске setup.py clean, Это создает довольно ироничную ситуацию с чистым шагом, иногда вызывающим компиляцию большого количества кода.

Как я уже сказал, эта зависимость установки требуется только для build шаг. Есть ли способ закодировать эту логику в setup.py, чтобы все команды, которые не вызывают команду сборки, выполнялись без нее?

2 ответа

Решение

Вы всегда можете заказать Distribution явным образом получить некоторые пакеты, так же, как они будут, если вы определите их в setup_requires, Пример с numpy зависимость требуется для build только команда:

from distutils.command.build import build as build_orig
from setuptools import setup, find_packages,  Command, dist


class build(build_orig):

    def run(self):
        self.distribution.fetch_build_eggs(['numpy'])
        # numpy becomes available after this line. Test it:
        import numpy
        print(numpy.__version__)
        super().run()

setup(
    name='spam',
    packages=find_packages(),
    cmdclass={'build': build,}
    ...
)

Зависимости передаются так же, как они будут определены в setup_requires arg, так что спецификации версии тоже в порядке:

self.distribution.fetch_build_eggs(['numpy>=1.13'])

Хотя я должен отметить, что выборка зависимостей через setup_requires обычно намного медленнее, чем их установка через pip (особенно если у вас есть тяжелые зависимости, которые сначала должны быть собраны из исходного кода), поэтому, если вы можете быть уверены, что у вас будет pip доступно ( или использовать python3.4и новее), подход, предложенный phd в его ответе, сэкономит ваше время. Однако выборка яиц через дистрибутив может оказаться полезной при сборке для старых версий python или неясных установок python, таких как системный python в MacOS.

if sys.argv[0] == 'build':
    kw = {'setup_requires': [req1, req2, …]}
else:
    kw = {}

setup(
    …,
    **kw
)

Другой подход, чтобы попробовать это переопределить build команда с кастомом cmdclass:

from setuptools.command.build import build as _build

class build(_build):
    def run(self):
        subprocess.call(["pip", "install", req1, req2…"])
        _build.run(self)

setup(
    …,
    cmdclass={'build': build},
)

и избегать setup_requires совсем.

Другие вопросы по тегам