wake-up-neo.com

Skript nach der Installation mit Python-Setuptools

Ist es möglich, eine Python-Skriptdatei nach der Installation als Teil der setuptools-Datei setup.py anzugeben, damit der Benutzer den Befehl ausführen kann:

python setup.py install

in einem lokalen Projektdateiarchiv oder

pip install <name>

für ein PyPI-Projekt und das Skript wird nach Abschluss der Standardinstallation von setuptools ausgeführt? Ich suche nach Aufgaben nach der Installation, die in einer einzigen Python-Skriptdatei codiert werden können (z. B. Übermittlung einer benutzerdefinierten Nachricht nach der Installation an den Benutzer, Abrufen zusätzlicher Datendateien aus einem anderen entfernten Quell-Repository).

Ich bin auf diese SO - Antwort von vor einigen Jahren gestoßen, die sich mit dem Thema befasst und es klingt, als ob der Konsens zu dieser Zeit war, dass Sie einen Installations-Unterbefehl erstellen müssen. Wenn dies immer noch der Fall ist, kann jemand ein Beispiel dafür angeben, wie dies getan werden muss, damit der Benutzer keinen zweiten Befehl eingeben muss, um das Skript auszuführen?

61
Chris Simpkins

Diese Lösung ist transparenter:

Sie werden einige Änderungen an setup.py vornehmen, und es ist keine zusätzliche Datei erforderlich. 

Außerdem müssen Sie zwei verschiedene Nachinstallationen berücksichtigen. eine für den Entwicklungs-/bearbeitbaren Modus und die andere für den Installationsmodus.

Fügen Sie diese beiden Klassen, die Ihr post-install -Skript enthalten, zu setup.py hinzu:

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)

und füge das cmdclass-Argument in die setup()-Funktion in setup.py ein:

setup(
    ...

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

    ...
)

Sie können sogar nach der Installation Shell-Befehle aufrufen:

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(
    ...

P.S. Es gibt keine vorinstallierten Einstiegspunkte für setuptools. Lesen Sie diese Diskussion wenn Sie sich fragen, warum es keine gibt.

52
mertyildiran

Dies ist die einzige Strategie, die für mich funktioniert hat, wenn für das Post-Install-Skript die Paketabhängigkeiten bereits installiert wurden:

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},
10
Apalala

Eine Lösung könnte darin bestehen, ein post_setup.py In das Verzeichnis von setup.py Aufzunehmen. post_setup.py Enthält eine Funktion, die die Nachinstallation ausführt, und setup.py Importiert und startet sie nur zum richtigen Zeitpunkt.

In 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 __== '__main__':
    setup(
        ...
        cmdclass={'install_data': my_install},
        ...
    )

In post_setup.py:

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

if __== '__main__':
    main()

Mit der üblichen Idee, setup.py Aus seinem Verzeichnis zu starten, können Sie post_setup.py Importieren, andernfalls wird eine leere Funktion gestartet.

In post_setup.py Können Sie mit der Anweisung if __== '__main__': Die Nachinstallation manuell über die Befehlszeile starten.

6
Zulu

Ich denke, der einfachste Weg, die Installation nach der Installation durchzuführen und die Anforderungen einzuhalten, besteht darin, den Aufruf an setup(...) zu dekorieren:

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=['...
    )
)

Dies wird setup() ausgeführt, wenn setup deklariert wird. Sobald die Installation der Anforderungen abgeschlossen ist, wird die Funktion _post_install() ausgeführt, die die innere Funktion _post_actions() ausführt.

2
Mbm

Wenn Sie atexit verwenden, müssen Sie keine neue Cmd-Klasse erstellen. Sie können Ihr atexit-Register einfach vor dem Aufruf von setup () erstellen. Es tut dasselbe.

Wenn Sie zunächst Abhängigkeiten installieren müssen, funktioniert nicht nicht mit pip install, da Ihr atexit-Handler aufgerufen wird, bevor pip die Pakete in Position bringt.

1
myjay610

Die Antworten von @Apalala, @Zulu und @mertyildiran kombinieren; Dies hat für mich in einer Python 3.5-Umgebung funktioniert:

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},
...

Dadurch haben Sie auch Zugriff auf den Installationspfad des Pakets in install_path, um einige Shell-Arbeiten auszuführen.

0
Ezbob