Настройка Python setuptools/distutils для пакета `extra` с Makefile

Преамбула: Python setuptools используются для распространения пакета. У меня есть пакет Python (назовем его my_package), у которого есть несколько пакетов extra_require. Все работает, просто найдите (установка и сборка пакета, а также дополнительные функции, если они были запрошены), поскольку все extra_require были самими пакетами python, и pip правильно разрешил все. Простой pip install my_package работал как шарм.

Настройка: Теперь для одной из дополнительных функций (назовем ее extra1) мне нужно вызвать двоичный код библиотеки, отличной от python X.

Сам модуль X (исходный код) был добавлен в кодовую базу my_package и был включен в дистрибутив my_package. К сожалению, для меня, X нужно сначала скомпилировать в двоичный файл на целевой машине (реализация на С++, я предполагаю, что такая компиляция должна произойти на этапе сборки установки my_package). В библиотеке X есть библиотека Makefile, оптимизированная для различной компиляции платформы, поэтому все, что необходимо, - это запустить make в соответствующем каталоге библиотеки X в my_package, когда выполняется процесс сборки,

Вопрос № 1: как запустить команду терминала (т.е. make в моем случае) во время процесса сборки пакета, используя setuptools/distutils?

Вопрос № 2: как обеспечить, чтобы такая команда терминала выполнялась только в том случае, если в процессе установки указан соответствующий extra1?

Пример:

  • Если кто-то запускает pip install my_package, такой дополнительной компиляции библиотеки X не будет.
  • Если кто-то запускает pip install my_package [extra1], необходимо скомпилировать модуль X, поэтому соответствующий файл будет создан и доступен на целевой машине.

Ответы

Ответ 1

К сожалению, документы крайне ограничены вокруг взаимодействия между setup.py и pip, но вы должны иметь возможность сделать что-то вроде этого:

import subprocess

from setuptools import Command
from setuptools import setup


class CustomInstall(Command):

    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        subprocess.call(
            ['touch',
             '/home/{{YOUR_USERNAME}}/'
             'and_thats_why_you_should_never_run_pip_as_sudo']
        )

setup(
    name='hack',
    version='0.1',
    cmdclass={'customcommand': CustomInstall}
)

Это дает вам возможность запускать произвольный код с помощью команд, а также поддерживает множество настраиваемых параметров (не показано здесь).

Поместите это в файл setup.py и попробуйте следующее:

pip install --install-option="customcommand" .

Обратите внимание, что эта команда выполняется после основной последовательности установки, поэтому в зависимости от того, что вы пытаетесь сделать, она может не работать. См. Вывод verbose pip install:

(.venv) ayoon:tmp$ pip install -vvv --install-option="customcommand" .
/home/ayoon/tmp/.venv/lib/python3.6/site-packages/pip/commands/install.py:194: UserWarning: Disabling all use of wheels due to the use of --build-options / -
-global-options / --install-options.                                                                                                                        
  cmdoptions.check_install_build_global(options)
Processing /home/ayoon/tmp
  Running setup.py (path:/tmp/pip-j57ovc7i-build/setup.py) egg_info for package from file:///home/ayoon/tmp
    Running command python setup.py egg_info
    running egg_info
    creating pip-egg-info/hack.egg-info
    writing pip-egg-info/hack.egg-info/PKG-INFO
    writing dependency_links to pip-egg-info/hack.egg-info/dependency_links.txt
    writing top-level names to pip-egg-info/hack.egg-info/top_level.txt
    writing manifest file 'pip-egg-info/hack.egg-info/SOURCES.txt'
    reading manifest file 'pip-egg-info/hack.egg-info/SOURCES.txt'
    writing manifest file 'pip-egg-info/hack.egg-info/SOURCES.txt'
  Source in /tmp/pip-j57ovc7i-build has version 0.1, which satisfies requirement hack==0.1 from file:///home/ayoon/tmp
Could not parse version from link: file:///home/ayoon/tmp
Installing collected packages: hack
  Running setup.py install for hack ...     Running command /home/ayoon/tmp/.venv/bin/python3.6 -u -c "import setuptools, tokenize;__file__='/tmp/pip-j57ovc7
i-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --
record /tmp/pip-_8hbltc6-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/ayoon/tmp/.venv/include/site/python3
.6/hack customcommand                                                                                                                                       
    running install
    running build
    running install_egg_info
    running egg_info
    writing hack.egg-info/PKG-INFO
    writing dependency_links to hack.egg-info/dependency_links.txt
    writing top-level names to hack.egg-info/top_level.txt
    reading manifest file 'hack.egg-info/SOURCES.txt'
    writing manifest file 'hack.egg-info/SOURCES.txt'
    Copying hack.egg-info to /home/ayoon/tmp/.venv/lib/python3.6/site-packages/hack-0.1-py3.6.egg-info
    running install_scripts
    writing list of installed files to '/tmp/pip-_8hbltc6-record/install-record.txt'
    running customcommand
done
  Removing source in /tmp/pip-j57ovc7i-build
Successfully installed hack-0.1