web-dev-qa-db-fra.com

Script post-installation avec Python setuptools

Est-il possible de spécifier un fichier de script Python post-installation dans le fichier setup.py de setuptools afin qu'un utilisateur puisse exécuter la commande:

python setup.py install

sur une archive de fichier de projet local, ou

pip install <name>

pour un projet PyPI et le script sera exécuté à la fin de l'installation standard de setuptools? Je souhaite effectuer des tâches de post-installation pouvant être codées dans un seul fichier de script Python (par exemple, délivrer un message de post-installation personnalisé à l'utilisateur, extraire des fichiers de données supplémentaires d'un autre référentiel source distant).

Je suis tombé sur cette SO réponse d'il y a plusieurs années qui aborde le sujet et on dirait que le consensus à l'époque était qu'il fallait créer une sous-commande install. Si tel est toujours le cas, serait-il possible pour quelqu'un de donner un exemple de la procédure à suivre pour qu'il ne soit pas nécessaire que l'utilisateur entre une deuxième commande pour exécuter le script?

61
Chris Simpkins

Cette solution est plus transparente:

Vous apporterez quelques ajouts à setup.py et il n’aura pas besoin d’un fichier supplémentaire. 

Aussi, vous devez considérer deux post-installations différentes; un pour le mode développement/éditable et l’autre pour le mode installation.

Ajoutez ces deux classes qui incluent votre script de post-installation à 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érez l'argument cmdclass de la fonction setup() dans setup.py:

setup(
    ...

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

    ...
)

Vous pouvez même appeler des commandes Shell pendant la post-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 pas de points d'entrée de pré-installation disponibles sur setuptools. Lisez cette discussion si vous vous demandez pourquoi il n'y en a pas. _

52
mertyildiran

C'est la seule stratégie qui a fonctionné pour moi lorsque le script de post-installation nécessite que les dépendances du package 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},
10
Apalala

Je pense que le moyen le plus simple d'effectuer la post-installation et de respecter les exigences consiste à 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=['...
    )
)

Ceci fonctionnera setup() lors de la déclaration de setup. Une fois l’installation des exigences terminée, il lancera la fonction _post_install(), qui exécutera la fonction interne _post_actions().

2
Mbm

Si vous utilisez atexit, il n'est pas nécessaire de créer une nouvelle cmdclass. Vous pouvez simplement créer votre registre atexit juste avant l'appel de setup (). Il fait la même chose.

De plus, si vous devez d'abord installer des dépendances, ceci pas fonctionne avec pip install puisque votre gestionnaire atexit sera appelé avant que pip ne déplace les paquets en place.

1
myjay610

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 dans install_path, sur lequel vous pourrez travailler.

0
Ezbob