Un guide pratique de l’utilisation de Setup.py

Données & Guide de formation AI 2021

Téléchargez la brochure GoDataDriven pour un aperçu complet des sessions de formation disponibles et des parcours d’apprentissage d’ingénierie des données, de science des données, d’analyste de données et de traducteur d’analyses.

Lorsque vous utilisez python de manière professionnelle, il est payant de configurer vos projets
de manière cohérente. Cela aide vos collaborateurs à comprendre rapidement la
structure d’un projet, et leur permet de configurer plus facilement le projet
sur leur machine. La clé de la mise en place de votre projet est le fichier setup.py.
Dans ce blog, j’entrerai dans les détails de ce fichier.

Où nous commençons

Je suppose ici que vous avez déjà un paquet que vous voulez mettre en place.
Il n’est pas nécessaire que ce soit un paquet fini – idéalement, vous devriez créer le
setup.py bien avant que votre projet soit terminé. Ce pourrait même être un paquet vide;
assurez-vous simplement que le dossier du paquet existe
et contient un fichier nommé init.py (qui peut être vide).

Si vous suivez la structure
de mon collègue Henk pour votre projet, votre situation de départ devrait ressembler à quelque chose comme ceci :

example_project/├── exampleproject/ Python package with source code.│ ├── __init__.py Make the folder a package.│ └── example.py Example module.└── README.md README with info of the project.

Vous pouvez avoir d’autres fichiers ou dossiers dans votre structure, par exemple
des dossiers nommés notebooks/, tests/ ou data/, mais ils ne sont pas nécessaires.

Le cas d’un setup.py

Une fois que vous avez créé un paquet comme celui-ci, alors vous êtes susceptible
d’utiliser une partie du code à d’autres endroits. Par exemple, vous pourriez vouloir
faire ceci dans un carnet de notes :

from exampleproject.example import example_function

Cela fonctionnerait si votre répertoire de travail actuel est example_project/, mais dans
tous les autres cas, python vous donnera une sortie comme :

ModuleNotFoundError: No module named 'exampleproject'

Vous pourriez indiquer à python où chercher le paquet en définissant la PYTHONPATH
variable d’environnement ou en ajoutant le chemin à sys.path,
mais c’est loin d’être idéal : cela nécessiterait différentes actions sur différentes
plateformes, et le chemin que vous devez définir dépend de l’emplacement de votre code.
Une bien meilleure façon est d’installer votre paquet en utilisant un setup.py et un pip,
car le pip est la façon standard d’installer tous les autres paquets, et il est voué
à fonctionner de la même façon sur toutes les plateformes.

Un exemple minimal

Alors, à quoi ressemble un fichier setup.py ? Voici un exemple minimal0:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', packages=find_packages(include=))

Nous spécifions ici trois choses :

  • Le nom du paquet, qui est le nom que pip utilisera pour votre paquet.
    Il n’est pas nécessaire que ce soit le même que le nom du dossier dans lequel le paquet vit
    , bien que cela puisse prêter à confusion si ce n’est pas le cas. Un exemple où le nom du paquet
    et le répertoire ne correspondent pas est Scikit-Learn : vous l’installez
    en utilisant pip install scikit-learn, alors que vous l’utilisez en l’important depuis sklearn.
  • La version de votre paquet. C’est la version que pip rapportera, et elle est utilisée
    par exemple lorsque vous publiez votre paquet sur PyPI1.
  • Quels paquets inclure ; dans notre cas, c’est juste exampleproject/.
    Ici nous laissons setuptools le déterminer
    automatiquement2. Bien que vous puissiez en principe utiliser find_packages()
    sans aucun argument, cela peut potentiellement entraîner l’inclusion de paquets non désirés
    . Cela peut se produire, par exemple,
    si vous avez inclus un __init__.pydans votre tests/
    répertoire. Alternativement, vous pouvez également utiliser l’argument exclude pour explicitement
    empêcher l’inclusion de tests dans le paquet, mais cela est légèrement
    moins robuste.

Maintenant, tout ce que vous devez faire pour installer votre paquet est d’exécuter ce qui suit
depuis l’intérieur du répertoire example_project/3:

pip install -e .

Le . fait ici référence au répertoire de travail actuel, que je suppose être le répertoire
où le setup.py peut être trouvé. Le drapeau -e spécifie que nous voulons installer
en mode modifiable, ce qui signifie
que lorsque nous modifions les fichiers de notre paquet, nous n’avons pas besoin de réinstaller le
paquet avant que les changements ne prennent effet. Vous devrez cependant soit redémarrer
python, soit recharger le paquet !

Lorsque vous modifiez des informations dans le setup.py lui-même, vous devrez réinstaller
le paquet dans la plupart des cas, et aussi si vous ajoutez de nouveaux (sous-)paquets.
En cas de doute, cela ne peut jamais faire de mal de réinstaller. Il suffit d’exécuter pip install -e . à nouveau.

Requirements

La plupart des projets ont quelques dépendances. Vous avez très probablement utilisé
un fichier requirements.txt
auparavant, ou un environment.yml
si vous utilisez conda. Maintenant que vous créez un setup.py, vous pouvez spécifier vos
dépendances dans l’argument install_requires.
Par exemple, pour un projet typique de science des données, vous pouvez avoir :

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=)

Vous pouvez spécifier des exigences sans version (PyYAML), épingler une version (pandas==0.23.3), spécifier une
version minimale ('numpy>=1.14.5) ou définir une plage de versions (matplotlib>=2.2.0,<3.0.0). Ces
exigences seront automatiquement installées par piplorsque vous installerez votre paquet.

Extras-require

Parfois, vous pouvez avoir des dépendances qui ne sont requises que dans certaines situations. En tant que data scientist
, je crée souvent des paquets que j’utilise pour entraîner un modèle. Lorsque je travaille sur un tel modèle de manière interactive
, je peux avoir besoin d’avoir matplotlib et jupyter installés afin de travailler interactivement avec les
données et de créer des visualisations
des performances du modèle. D’autre part, si le modèle tourne en production, je ne
veux pas installer matplotlib ni jupyter sur la machine (ou le conteneur) où je m’entraîne
ou fais de l’inférence. Heureusement setuptools permet de spécifier des dépendances optionnelles dans extras_require:

setup( name='example', version='0.1.0', packages=find_packages(include=), install_requires=, extras_require={ 'interactive': , })

Maintenant si nous installons le paquet normalement (pip install example depuis PyPI ou pip install -e . localement)
il n’installera que les dépendances PyYAML, pandas et numpy. Cependant, lorsque nous spécifions
que nous voulons les dépendances interactiveoptionnelles (pip install example
ou pip install -e .),
alors matplotlib et jupyter seront également installées.

Scripts et points d’entrée

Le principal cas d’utilisation de la plupart des paquets python que vous installez à partir de PyPI est de fournir des fonctionnalités
qui peuvent être utilisées dans d’autres codes python. En d’autres termes, vous pouvez importde ces paquets.
En tant que scientifique des données, je fais souvent des paquets qui ne sont pas destinés à être utilisés par d’autres codes python mais
sont destinés à faire quelque chose, par exemple à entraîner un modèle. En tant que tel, j’ai souvent un script python que
je veux exécuter à partir de la ligne de commande.

La meilleure façon4 d’exposer la fonctionnalité de votre paquet à la ligne de commande est de définir
un entry_point comme tel:

setup( # ..., entry_points={ 'console_scripts': })

Maintenant vous pouvez utiliser la commande my-command à partir de la ligne de commande, qui à son tour exécutera la main
fonction à l’intérieur de exampleproject/example.py. N’oubliez pas de réinstaller – sinon la commande
ne sera pas enregistrée.

Tests

Chaque fois que vous écrivez un code, je vous encourage fortement à écrire également des tests pour ce code. Pour les tests
avec python, je vous suggère d’utiliser pytest. Bien sûr, vous ne voulez pas ajouter pytest à vos dépendances
en install_requires : il n’est pas requis par les utilisateurs de votre paquet. Afin qu’il soit installé
automatiquement lorsque vous exécutez des tests, vous pouvez ajouter ce qui suit à votre setup.py:

setup( # ..., setup_requires=, tests_require=,)

En outre, vous devrez créer un fichier nommé setup.cfg avec le contenu suivant:

test=pytest

Maintenant, vous pouvez simplement exécuter python setup.py test et setuptools s’assurera que les dépendances nécessaires
sont installées et exécutera pytest pour vous ! Jetez un œil ici si
vous voulez fournir des arguments ou définir des options de configuration pour pytest.

Si vous avez des exigences supplémentaires pour les tests (par exemple pytest-flask), vous pouvez les ajouter à tests_require.

Flake8

Personnellement, je pense que c’est une bonne idée d’exécuter Flake8 pour
vérifier le formatage de votre code. Tout comme avec pytest, vous ne voulez pas ajouter flake8 aux
install_requires dépendances : il n’a pas besoin d’être installé pour utiliser votre
package. Au lieu de cela, vous pouvez l’ajouter à setup_requires:

setup( # ..., setup_requires=)

Maintenant, vous pouvez simplement exécuter python setup.py flake8. Bien sûr, vous pouvez aussi épingler la version
de flake8 (ou tout autre paquet) dans setup_requires:

Si vous voulez changer certains des paramètres de configuration de Flake8, vous pouvez ajouter une section à
votre setup.cfg. Par exemple :

max-line-length=120

Données du paquet

Parfois, vous pouvez vouloir inclure certains fichiers nonython dans votre paquet. Ceux-ci
peuvent par exemple être des fichiers de schéma ou une petite table de consultation. Soyez conscient que de tels fichiers
seront empaquetés avec votre code, donc c’est en général une mauvaise idée d’inclure
tous les gros fichiers.

Supposons que nous avons un schema.json dans notre projet, que nous plaçons dans exampleproject/data/schema.json.
Si nous voulons l’inclure dans notre paquet, nous devons utiliser l’argument package_data de setup:

setup( # ..., package_data={'exampleproject': })

Cela fera en sorte que le fichier soit inclus dans le paquet. Nous pouvons également choisir d’inclure
tous les fichiers en fonction d’un motif, par exemple:

setup( # ..., package_data={'': })

Cela ajoutera tous les *.jsonfichiers dans tout paquet qu’il rencontre.

N’essayez pas maintenant de déterminer vous-même l’emplacement des fichiers installés, car
pkg_resources a des fonctions de commodité très pratiques :

  • pkg_resources.resource_stream vous donnera un flux du fichier, un peu comme l’objet
    que vous obtenez lorsque vous appelez open(),
  • pkg_resources.resource_string vous donnera le contenu du fichier sous forme de chaîne,
  • pkg_resources.resource_filename vous donnera le nom de fichier du fichier (et l’extraira
    dans un temporaire s’il est inclus dans un paquet zippé) pour si les deux options
    ci-dessus ne répondent pas à vos besoins.

Par exemple, nous pourrions lire dans notre schéma en utilisant :

from json import loadfrom pkg_resources import resource_streamschema = load(resource_stream('exampleproject', 'data/schema.json'))

Métadonnées

Si vous allez publier votre paquet, alors vous voulez probablement donner à vos
utilisateurs potentiels quelques informations supplémentaires sur votre paquet, y compris une description,
le nom de l’auteur ou du mainteneur, et l’url de la page d’accueil du paquet.
Vous pouvez trouver une liste complète de toutes les métadonnées autorisées dans les setuptools
docs.

En outre, si vous allez publier sur PyPI, alors vous pouvez vouloir
charger automatiquement le contenu de votre README.md
dans le long_description,
et fournir des classificateurs pour dire pipencore plus
sur votre paquet.

Wrap-up

Ce blog devrait être un bon point de départ pour mettre en place la plupart de vos projets python.
Si vous voulez en savoir plus sur le packaging python, jetez un coup d’œil
à la docs. Voici un exemple setup.py
qui combine toutes les parties montrées dans ce blog:

from setuptools import setup, find_packagessetup( name='example', version='0.1.0', description='Setting up a python package', author='Rogier van der Geer', author_email='[email protected]', url='https://blog.godatadriven.com/setup-py', packages=find_packages(include=), install_requires=, extras_require={'plotting': }, setup_requires=, tests_require=, entry_points={ 'console_scripts': }, package_data={'exampleproject': })

et le setup.cfg qui l’accompagne:

test=pytestmax-line-length=120

Améliorez vos compétences en Python, apprenez des experts!

À GoDataDriven, nous offrons une foule de cours sur Python, du débutant à l’expert, enseignés par les meilleurs professionnels du domaine. Rejoignez-nous et mettez votre jeu Python à niveau :

  • Python Essentials – Idéal si vous débutez avec Python.
  • Certified Data Science with Python Foundation – Vous voulez passer de l’analyse et de la visualisation des données à la véritable science des données ? C’est le bon cours.
  • Science avancée des données avec Python – Apprenez à mettre en production vos modèles comme un pro et utilisez Python pour l’apprentissage automatique.
Footnotes

0 : Dans ce blog, j’ai utilisé setuptools
pour configurer mon projet d’exemple. Alternativement
vous pourriez aussi utiliser distutils,
qui est l’outil standard pour le packaging en python, mais il manque de fonctionnalités
comme la fonction find_packages()et entry_points.
Puisque l’utilisation de setuptools est très courante de nos jours et que beaucoup de ses fonctionnalités
peuvent être particulièrement utiles, je vous suggère d’utiliser setuptools.

1 : Si vous voulez que la version de votre paquet soit également disponible à l’intérieur de python,
jetez un œil ici.

2 : Vous pourriez également lister vos paquets manuellement, mais cela est particulièrement sujet aux erreurs.

3 : Alternativement, vous pourriez exécuter python setup.py install, mais l’utilisation de pip a
de nombreux avantages, parmi lesquels l’installation automatique des dépendances et la
possibilité de désinstaller ou de mettre à jour votre paquet.

4 : Vous pourriez également utiliser l’argument scripts (voir pour
exemple ici)
mais comme cela nécessite de créer un script shell python, cela peut ne pas fonctionner
aussi bien (ou pas du tout) sous Windows.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.