Post-installation script avec Python setuptools

est-il possible de spécifier un fichier de script Python post-install dans le cadre des setuptools setup.py fichier pour qu'un utilisateur puisse exécuter la commande:

python setup.py install

sur un fichier local d'archives de projet, ou

pip install <name>

pour un projet PyPI et le script sera lancé à la fin de l'installation standard de setuptools? Je suis à la recherche d'effectuer des tâches post-installation qui peuvent être codées dans un seul fichier de script Python (par ex. après l'installation, un message à l'utilisateur, tirez des fichiers de données supplémentaires à partir d'une autre source à distance référentiel).

je suis tombé sur cette AFIN de répondre à plusieurs années qui aborde le sujet et il semble que le consensus était à cette époque que vous avez besoin pour créer une installation sous-commande. Si c'est toujours le cas, serait-il possible pour quelqu'un de donner un exemple de comment faire en sorte qu'il n'est pas nécessaire pour l'utilisateur de saisir une deuxième commande pour lancer le script?

52
demandé sur Community 2013-11-29 19:11:59

5 réponses

Cette solution est plus transparente:

vous allez faire quelques ajouts à setup.py et il n'y a pas besoin d'un fichier supplémentaire.

vous devez également considérer deux post-installations différentes; une pour le mode de développement/modifiable et l'autre pour le mode d'installation.

ajoutez ces deux classes qui incluent votre post-installation script à 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)

et insérer cmdclass argument à setup() fonction dans setup.py :

setup(
    ...

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

    ...
)

vous pouvez même appeler des commandes shell après l'installation, comme ceci:

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. Il n'y a aucun point d'entrée pré-installation disponible sur les outils de setuptools. Lisez cette discussion si vous vous demandez pourquoi il n'y en a pas.

45
répondu mertyildiran 2017-10-05 22:36:00

C'est la seule stratégie qui a fonctionné pour moi lorsque le script de post-installation exige que les dépendances du paquet aient déjà été installées:

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},
9
répondu Apalala 2017-03-07 12:39:06

une solution pourrait être d'inclure un post_setup.py dans le répertoire de setup.py . post_setup.py contiendra une fonction qui effectue la post-installation et setup.py ne l'importera et ne la lancera qu'au moment approprié.

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

Dans post_setup.py :

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

if __name__ == '__main__':
    main()

avec l'idée courante de lancer setup.py à partir de son répertoire, vous pourrez importer post_setup.py sinon il lancera une fonction vide.

dans post_setup.py , la déclaration if __name__ == '__main__': vous permet de lancer manuellement une post-installation à partir de la ligne de commande.

6
répondu Zulu 2017-05-22 14:34:14

je pense que la façon la plus facile d'effectuer la post-installation, et de garder les exigences, est de décorer l'appel à 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=['...
    )
)

ce sera setup() en déclarant setup . Une fois fait avec l'installation des exigences, il exécutera la fonction _post_install() , qui exécutera la fonction interne _post_actions() .

2
répondu Mbm 2018-06-07 12:52:37

combinant les réponses de @Apalala, @Zulu et @mertyildiran; cela a fonctionné pour moi dans un environnement 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},
...

Cela vous donne également accès au chemin d'installation du paquet install_path , pour faire de la shell.

0
répondu Ezbob 2017-03-28 19:15:30