Подтвердить что ты не робот

После установки script с Python setuptools

Можно ли указать пост-установочный файл Python script как часть файла setup.py setuptools, чтобы пользователь мог выполнить команду:

python setup.py install

в локальном архиве файлов проекта или

pip install <name>

для проекта PyPI и script будет запущен при завершении установки стандартного setuptools? Я ищу для выполнения задач после установки, которые могут быть закодированы в одном файле Python script (например, доставить пользовательское сообщение после установки пользователю, вытащить дополнительные файлы данных из другого репозитория удаленного источника).

Я встретил этот ответ SO от нескольких лет назад, который затрагивает тему, и звучит так, как будто в то время консенсус заключался в том, что вам нужно создать подкоманду install, Если это так, возможно, кому-то будет предоставлен пример того, как это сделать, чтобы пользователю не нужно вводить вторую команду для запуска script?

4b9b3361

Ответ 1

Это решение более прозрачно:

Вы сделаете несколько дополнений в setup.py, и вам не понадобится дополнительный файл.

Также вам нужно рассмотреть две различные пост-установки; один для режима разработки/редактирования и другой для режима установки.

Добавьте эти два класса, которые включают ваш скрипт после установки, в setup.py:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install


class PostDevelopCommand(develop):
    """Post-installation for development mode."""
    def run(self):
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION
        develop.run(self)

class PostInstallCommand(install):
    """Post-installation for installation mode."""
    def run(self):
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION
        install.run(self)

и вставьте аргумент cmdclass в функцию setup() в setup.py:

setup(
    ...

    cmdclass={
        'develop': PostDevelopCommand,
        'install': PostInstallCommand,
    },

    ...
)

Вы можете даже вызывать команды оболочки во время пост-установки, например:

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from subprocess import check_call


class PostDevelopCommand(develop):
    """Post-installation for development mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        develop.run(self)

class PostInstallCommand(install):
    """Post-installation for installation mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        install.run(self)


setup(
    ...

PS в setuptools нет предустановленных точек входа. Прочтите эту дискуссию, если вам интересно, почему ее нет.

Ответ 2

Это единственная стратегия, которая работала для меня, когда post-install script требует, чтобы зависимости пакета уже были установлены:

import atexit
from setuptools.command.install import install


def _post_install():
    print('POST INSTALL')


class new_install(install):
    def __init__(self, *args, **kwargs):
        super(new_install, self).__init__(*args, **kwargs)
        atexit.register(_post_install)


setuptools.setup(
    cmdclass={'install': new_install},

Ответ 3

Решением может быть включение каталога post_setup.py в setup.py. post_setup.py будет содержать функцию, которая после установки и setup.py будет импортировать и запускать ее в соответствующее время.

В setup.py:

from distutils.core import setup
from distutils.command.install_data import install_data

try:
    from post_setup import main as post_install
except ImportError:
    post_install = lambda: None

class my_install(install_data):
    def run(self):
        install_data.run(self)
        post_install()

if __name__ == '__main__':
    setup(
        ...
        cmdclass={'install_data': my_install},
        ...
    )

В post_setup.py:

def main():
    """Do here your post-install"""
    pass

if __name__ == '__main__':
    main()

С общей идеей запуска setup.py из его каталога вы сможете импортировать post_setup.py else, и он запустит пустую функцию.

В post_setup.py оператор if __name__ == '__main__': позволяет вручную запускать пост-установку из командной строки.

Ответ 4

Я думаю, что самый простой способ выполнить постустановку и соблюсти требования, это украсить вызов 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().

Ответ 5

При использовании atexit нет необходимости создавать новый cmdclass. Вы можете просто создать свой регистр atexit прямо перед вызовом setup(). Это делает то же самое.

Кроме того, если вам нужно сначала установить зависимости, это не работает с установкой pip, так как ваш обработчик atexit будет вызван до того, как pip переместит пакеты на место.

Ответ 6

Объединение ответов от @Apalala, @Zulu и @mertyildiran; это сработало для меня в среде Python 3.5:

import atexit
import os
import sys
from setuptools import setup
from setuptools.command.install import install

class CustomInstall(install):
    def run(self):
        def _post_install():
            def find_module_path():
                for p in sys.path:
                    if os.path.isdir(p) and my_name in os.listdir(p):
                        return os.path.join(p, my_name)
            install_path = find_module_path()

            # Add your post install code here

        atexit.register(_post_install)
        install.run(self)

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

Это также дает вам доступ к пути установки пакета в install_path, чтобы работать с некоторыми командами.