Python: les dépendances

Sommaire

Intro

Dans le cadre de mon travail, j’ai régulièrement besoin d’écrire des scripts en python ou bien des notebook Jupyter. Je n’ai pas particulièrement d’affinité avec ce langage, disons qu’il s’est imposé à moi :-) En revanche, il y a quelque chose qui me chagrine, c’est la gestion des dépendances. C’est particulièrement agaçant de reprendre un script et de voir que les dépendances ne sont pas indiquées ou bien il manque leur version et loi de Murphy oblige, l’API a bougé… Bref, je peux lister les problématiques suivantes dans la gestion des dépendances de mes projets python:

On peut déjà indiquer quelques solutions qui font consensus pour gérer une partie de ces problèmes. En particulier, on peut commencer par lister nos dépendances dans un fichier texte. Si vous utilisez pip pour installer vos dépendances, il dispose d’une solution standardisée: requirements.txt

Cette solution permet de résoudre nos deux premiers problèmes:

Cependant lorsqu’on reprend un vieux script, il arrive parfois que la version indiquée dans le fichier requirements.txt ne soit plus distribué sous format binaire par pypi. Il faut alors compiler nous-même cette dépendance. Un cas concret: si je reprends mon exemple précédent mais que je fixe numpy == 2.0.*, une version qui a un peu plus de deux ans lorsque j’écris ces lignes. Pypi ne propose plus de télécharger directement les fichiers pré-compilés (wheels). pip va donc télécharger les sources et compiler le projet sur votre ordinateur. C’est à ce moment-là que ça peut se compliquer. En effet, certain projet ont la réputation d’être difficile à compiler. Maintenant extrapolons cette situation sur toute une cascade de dépendances, et vous apercevez la profondeur du gouffre…

Rappelons-le, à la base on souhaitait simplement re-utiliser un script sur un vieux projet ;-)

Zig

Un autre langage que j’utilise régulièrement: zig, je l’apprécie pour bien des raisons et l’une d’entre elles est sa gestion des dépendances. Pour résumer trivialement (explications valable pour la version 0.16.0 et 0.17.x, ces caractéristiques sont susceptibles d’évoluer):

Pour plus d’informations, n’hésitez pas à lire ce post: Two Package Management Workflow Enhancements.

Pourquoi je vous parle de ça ? Parque j’aimerai bien retrouver un comportement similaire pour mes scripts en python…

Dépendances Python à la Zig

La première fonctionnalité et sûrement la plus simple, la gestion d’un fork. pip gère nativement ce problème, il vous suffit d’installer la dépendance avec la commande suivante:

pip install -e path/to/project

Si votre paquet était déjà présent dans votre installation alors pip va le supprimer et ajouter le répertoire de votre projet à la liste des chemins d’import. Et c’est tout. Maintenance lorsque vous modifier votre fork en local, les changements sont directement prient en compte dans votre projet.

Récupération des dépendances

Passons maintenant à la partie récupération en local des dépendances. On commence par créer un répertoire py-pkg à la racine de votre projet. Maintenant, on va se servir de pip pour télécharger l’ensemble des dépendances dans ce répertoire:

py -m pip download --destination-directory py-pkg -r requirements.txt

pip va télécharger les fichiers wheels de l’ensemble des dépendances dans ce dossier, mais aussi des dépendances de vos dépendances et ainsi de suite.

Attention

Less fichiers wheels sont des fichiers binaires dépendant de la plateforme cible (car compilés). On peut toujours télécharger les sources avec la commande py -m pip download --no-binary :all: mais la doc le déconseille, car certain paquet sont difficiles à compiler… De plus, après avoir testé, ça ne télécharge que la dépendance et non toutes l’arborescence de dépendances…

Configuration à partir d’une archive

Il n’est pas conseillé d’ajouter ces versions à votre VCS, car ce sont des fichiers binaires dépendants de votre plateforme, mais vous pouvez au moins les ajouter à votre archive lorsque vous taguez une nouvelle version de votre script.

Maintenant, on peut installer les dépendances de notre projet à partir de leur archive:

py -m venv .env
source .env/bin/activate
py -m pip install --no-index --find-links=py-pkg -r requirements.txt

Quelques liens utiles

Conclusion

Cette solution ne permet pas d’obtenir un fonctionnement calqué sur celui de zig. Cependant, elle permet de pérenniser l’archivage de vos scripts et de ses dépendances. En effet, en archivant les fichiers wheel de votre projet vous vous assurez de pouvoir le réutiliser sans soucis le jour venu. Enfin, si vous disposez toujours d’un interpréteur python compatible…

Ces problèmes n’en finiront jamais ;-)