Il est en effet assez facile de s’y perdre lors de la gestion des compatibilités entre les différentes versions des packages Python mais aussi et surtout avec les multiples versions de Python à disposition. Nous allons voir à l’aide ce billet de blog une solution nommée Poetry qui promet de nous faciliter la tâche et de rendre le packaging, le build ainsi que le déploiement de nos applications Python aussi simple que possible.
Poetry: les concepts
Projet open source, Poetry se base essentiellement sur des outils assez classiques dans le développement des projets Python tel que pip, venv ou pyenv mais apporte une surcouche qui change l’expérience développeur. Un projet géré par Poetry se base essentiellement sur deux fichiers : <code class="inline-code-element">pyproject.toml</code>et <code class="inline-code-element">poetry.lock</code>
Regardons ce que contiennent ces deux fichiers.
pyproject.toml
À l’initialisation de votre projet il est composé de :
- <code class="inline-code-element">tool.poetry</code> : renseigne des informations sur votre projet (nom, version, description et auteur)
- <code class="inline-code-element">tool.poetry.dependencies</code> : les dépendances du projet installées dans un environnement de production
- <code class="inline-code-element">tool.poetry.dev-dependencies</code> : les dépendances du projet installées dans un environnement de dev
Cette distinction entre l’environnement de dev et celui de production nous permet en tant que développeur d’avoir des versions différentes de nos packages ou de nouvelles dépendances qu’il est inutile d’avoir en environnement de production, il est ainsi possible de tester de nouvelles fonctionnalités de manière sereine et isolée sans avoir à installer et ensuite désinstaller ces packages.
Il aura ainsi cette configuration à la création d’un projet nommé, par exemple <code class="inline-code-element">poetry-demo</code> :
Le fichier <code class="inline-code-element">pyproject.toml</code> peut incorporer à lui seul le contenu des fichiers <code class="inline-code-element">requirements.txt</code>, <code class="inline-code-element">setup.py</code>, <code class="inline-code-element">setup.cfg</code>, <code class="inline-code-element">MANIFEST.in</code> ainsi que le fichier <code class="inline-code-element">Pipfile</code> . L’ensemble des fonctionnalités qu’il est possible d’intégrer sont listées ici.
Notez aussi l’utilisation de wildcard <code class="inline-code-element">python = "*" </code> ou encore <code class="inline-code-element">pytest = "^7.1"</code> pour spécifier les versions de vos dépendances, cette manière de faire offre la possibilité de maitriser les futurs versions que Poetry va installer dans le cas d’un update. Elles ne sont pas forcément figées à une version particulière. Nous y reviendrons un peu plus tard dans l’article.
poetry.lock
Une fois vos dépendances installées, Poetry génère un fichier <code class="inline-code-element">poetry.lock</code> qui centralise toutes les versions exactes de votre projet Python. Ce fichier est capital pour figer les versions des dépendances utilisées. En effet, étant donné que dans le fichier <code class="inline-code-element">pyproject.toml</code> les versions citées ne sont pas précises avec l’utilisation des wildcards et qu’ils sont souvent amenées à évoluer dans le cas d’une mise à jour, le fichier <code class="inline-code-element">poetry.lock</code> les renseigne et nous garantit que si ces versions exactes sont installées, alors le projet peut être construit.
C’est une bonne pratique de rajouter le fichier <code class="inline-code-element">poetry.lock</code> à git pour garantir aux développeurs (y compris vous même), à votre CI ou encore vos serveurs de production la résilience de votre projet en cas d’une nouvelle release de vos dépendances.
Le fichier <code class="inline-code-element">pyproject.toml</code> représente la vision à long terme des dépendances en cas d’update, ce qui nous permet d’être serein si un update à lieu. Le fichier <code class="inline-code-element">poetry.lock</code> quand à lui fige les versions avec lequelles le programme marche en ce temps T (ce qui assure que le code n’aura pas de conflit de dépendances sur aucune des machines (local, sur la CI, en production,
Poetry: dans la vraie vie
La surcouche apportée dans Poetry nous apporte une facilité déconcertante dans le développement des projets Python, ainsi il suffit de lancer les commandes suivantes pour:
- Créer/Activer un virtual environment:
- Ajouter supprimer ou updater une dépendance:
Cette requête est très utile pour avoir une idée claire des versions utilisées, elle a pour résultat une sorte d’arbre qui contient les dépendances, leurs versions mais aussi les sous dépendances installées, voici son retour pour le projet de démo:
- Installer les dépendances:
Poetry récupère l’ensemble des versions à installer à partir du fichier <code class="inline-code-element">poetry.lock</code> s’il est existant. Et s’il n’existe pas (au début du projet par exemple), Poetry se base sur le fichier <code class="inline-code-element">pyproject.toml</code> pour récupérer les dernières versions disponibles des packages cités.
- Build son application:
Cette commande génère un fichier <code class="inline-code-element">.wheel</code> et un fichier<code class="inline-code-element">.sdist</code> qui représentent votre projet sous forme de package livrable et réutilisable.
- Publier son application:
Cette commande permet de déployer votre projet dans un repository privé qui a été préalablement configuré. Si l’option -r n’est pas spécifiée, le déploiement se fera dans pypi.
- Exécuter du code python:
- Changer d’environnement Python:
- Lancer les tests unitaires avec pytest:
Spécifier la version des dépendances avec Poetry
Comme cité plus haut, il est possible de configurer précisément les nouvelles versions de nos dépendances que Poetry est amené à installer lors d’une commande d’update. Géré par des wildcards, cette manière de faire nous permet d’assurer une actualisation de nos dépendances en évitant, si on le souhaite, de passer à des versions majeures pour éviter de casser la compatibilité.
Par exemple, pour spécifier qu’une dépendance ne peut être actualisée en version majeure on peut utiliser la syntaxe suivante dans votre fichier <code class="inline-code-element">pyproject.toml</code> :
Cette spécification permettra de mettre à jour le package pytest jusqu’à la version 1.3.0. Ainsi, si une version majeure 2.0.0 est amenée à exister, elle ne sera pas installée pour éviter d’avoir des erreurs de rétro-compatibilité. Pour voir l’ensemble des possibilités que propose Poetry concernant les wlidcards, tout est listé ici.
Conclusion
Poetry regroupe à lui seul un ensemble d’outils que l’on devait auparavant utiliser individuellement pour faire vivre nos projets Python (pyenv, venv, pip, twine, ...). Et il fait bien plus que cela, en s’assurant d’avoir toujours un projet qui a des dépendances à jour sans forcément casser la compatibilité.