Выполните скрипт установки Python после установки, используя distutils / setuptools

Я пытаюсь добавить задачу после установки в дистрибутив Python, как описано в разделе Как расширить distutils с помощью простого скрипта после установки?, Задача должна выполнить скрипт Python в установленной директории lib. Этот скрипт генерирует дополнительные модули Python, необходимые для установленного пакета.

Моя первая попытка выглядит следующим образом:

from distutils.core import setup
from distutils.command.install import install

class post_install(install):
    def run(self):
        install.run(self)
        from subprocess import call
        call(['python', 'scriptname.py'],
             cwd=self.install_lib + 'packagename')

setup(
 ...
 cmdclass={'install': post_install},
)

Этот подход работает, но, насколько я могу судить, имеет два недостатка:

  1. Если пользователь использовал интерпретатор Python, отличный от того, который был взят из PATHсценарий после установки будет выполнен с другим интерпретатором, который может вызвать проблему.
  2. Это небезопасно против пробного запуска и т. Д., Который я мог бы исправить, обернув его в функцию и вызвав его distutils.cmd.Command.execute,

Как я могу улучшить свое решение? Есть ли рекомендуемый способ / лучшие практики для этого? Я хотел бы, если это возможно, избежать другой зависимости.

2 ответа

Решение

Способ устранения этих недостатков:

  1. Получить полный путь к выполнению интерпретатора Python setup.py от sys.executable,
  2. Классы, наследуемые от distutils.cmd.Command (такие как distutils.command.install.install который мы используем здесь) реализовать execute метод, который выполняет данную функцию "безопасным способом", то есть с соблюдением флага пробного запуска.

    Обратите внимание, что --dry-run опция в настоящее время не работает и не работает как задумано.

Я получил следующее решение:

import os, sys
from distutils.core import setup
from distutils.command.install import install as _install


def _post_install(dir):
    from subprocess import call
    call([sys.executable, 'scriptname.py'],
         cwd=os.path.join(dir, 'packagename'))


class install(_install):
    def run(self):
        _install.run(self)
        self.execute(_post_install, (self.install_lib,),
                     msg="Running post install task")


setup(
    ...
    cmdclass={'install': install},
)

Обратите внимание, что я использую имя класса install для моего производного класса, потому что это то, что python setup.py --help-commands буду использовать.

Я думаю, что самый простой способ выполнить постинсталляцию и сохранить требования - это украсить вызов setup(...):

from setup tools import setup


def _post_install(setup):
    def _post_actions():
        do_things()
    _post_actions()
    return setup

setup = _post_install(
    setup(
        name='NAME',
        install_requires=['...
    )
)

Это будет работать setup() при объявлении setup, После установки с требованиями, он запустит _post_install() функция, которая будет запускать внутреннюю функцию _post_actions(),

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