Python, gestion des packages et des dépendances

Lorsqu’il s’agit de démarrer un produit pour le NetDevOps en langage Python, la principale préoccupation est la gestion des dépendances. Les dépendances font références à tous les composants logiciels requis par le produit pour qu’il fonctionne.

PyPI (Python Package Index) fournit des packages qui aident à démarrer un produit sur tout type de sujet, mais outre le fait qu’il convient de ne pas installer les packages au niveau du système, il peut être nécessaire de gérer des versions différentes d’environnements de développement pour un même produit, avec une gestion pointue des dépendances et de leurs éventuels conflicts.

Pip est l’outil standard pour installer les packages Python et gérer leurs dépendances. En utilisant pip pour installer des packages, il les récupère automatiquement avec toutes ses dépendances à partir du Python Package Index (PyPI) et les installe localement sur le système. De façon à ne pas installer l’environnement de développement de façon globale sur le système, mais plutôt de l’isoler, le recours à un environnement virtuel Python est fortement recommandé.

L’approche la plus traditionnelle est la suivante :

python3 -m venv /path/to/new/virtual/environment
source <venv>/bin/activate
pip install -r requirements.txt

Le fichier requirements.txt peut ne spécifier que les noms des packages souhaités ou alors donner des directives de version à l’aide des opérateurs ==>>=<<= qui peuvent être combinés.

Très rapidement, il est apparu nécessaire de perfectionner cette approche. Dans un premier temps ce sont des utilitaires Python qui ont été proposés pour automatiser la création et l’activation d’un environnement virtuel. Mais pour aller plus loin, des outils plus sophistiqués ont été mis au point. Les outils comme Pipenv, Poetry, et Conda sont ceux qui sont le plus souvent utilisés.

Pipenv

Pipenv est un outil qui vise à apporter, à Python, le meilleur de tout ce qu’on peut trouver dans le monde du packaging. Il crée et gère automatiquement un virtualenv pour les produits, et il ajoute et supprime des packages du Pipfile lorsqu’on en installe ou désinstalle. Il génère également le très important Pipfile.lock, qui est utilisé pour produire des versions déterministes.

Pipenv vise à résoudre des problèmes tels que :

  • Plus besoin d’utiliser pip et virtualenv séparément, car ils sont combinés dans l’outil Pipenv.
  • Le fichier requirements.txt nest plus nécessaire car Pipenv utilise Pipfile et Pipfile.lock pour séparer les déclarations de dépendance abstraites de la dernière combinaison testée.
  • Par soucis de sécurité, les hachages sont utilisés partout.
  • La solution Pipenv encourage fortement l’utilisation des dernières versions des dépendances afin de minimiser les risques de sécurité découlant de composants obsolètes.
  • On dispose d’un aperçu de votre graphique des dépendances.
  • On peut rationaliser le workflow de développement en chargeant des fichiers .env.

Je vais être très direct, je n’aime pas cette solution qui n’a pas un comportement homogène et stable en fonction des distributions des versions Python et des systèmes d’exploitation.

Conda

Conda est un système de gestion de packages Open Source et un système de gestion d’environnement qui s’exécute sous Windows, macOS et Linux. Conda installe, exécute et met à jour rapidement les packages et leurs dépendances. Conda crée, enregistre, charge et bascule facilement entre les environnements sur votre ordinateur local. Il a été créé pour les programmes Python, mais il peut empaqueter et distribuer des logiciels pour n’importe quel langage tel que R, Ruby, Lua, Scala, Java, JavaScript, C/ C++ et FORTRAN.

Alors que tous les outils présentés s’appuient sur PyPI, Conda possède ses propres ressources. C’est une solution très complète et qui est souvent utilisée, mais que je trouve anormalement lourde pour l’usage qui nous concerne dans le domaine du NetDevOps.

Poetry

Poetry est un outil de gestion des dépendances et de packaging pour Python. Il permet de déclarer les librairies dont dépend le produit et il les gère (installer/mettre à jour). Il offre la possibilité de construire facilement un package à partir du produit, de publier rapidement un travail sur PyPI et de suivre simplement les dépendances du produit.

Poetry est livré avec un résolveur de dépendances exhaustif, qui trouvera toujours une solution si elle existe. Si aucune solution n’existe, alors il fournira une explication détaillée. Poetry utilise les environnements virtuels existants ou il créé le sien pour toujours être isolé du système. Les commandes sont intuitives et faciles à utiliser, avec des valeurs par défaut qui restent configurables. L’outil peut être étendu avec le système de plugin.

L’installation de Poetry tient en une ligne (veiller à avoir le path configuré) :

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -

La création d’une nouvelle application passe par la commande poetry new myapp et une nouvelle arborescence de répertoire est créée.

Répertoire projet poetry
Répertoire produit poetry

Pour l’instant, le fichier le plus important est pyproject.toml, c’est lui qui orchestre le produit et ses dépendances. Après la création d’un nouveau produit, son contenu minimal est le suivant :

[tool.poetry]
name = "myapp"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.10"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

L’activation de l’environnement virtuel se fait à l’aide la commande poetry shell, avec pour conséquence la création d’un répertoire virtualenvs dans /home/gilbert/.cache/pypoetry/. La sortie de l’environnement virtuel s’effectue avec la commande exit.

Après configuration du fichier pyproject.toml, l’installation des dépendances du produit nécessite le lancement de poetry install. Lors de la première exécution de la commande, il est probable qu’aucun fichier poetry.lock ne soit présent. Poetry résout toutes les dépendances répertoriées dans le fichier pyproject.toml et télécharge la dernière version de leurs fichiers.

Lorsque Poetry a terminé l’installation, il écrit tous les packages et leurs versions exactes téléchargées dans le fichier poetry.lock, verrouillant le produit sur ces versions spécifiques. Il est nécessaire de valider le fichier poetry.lock dans le référentiel de produit (serveur de versioning) afin que toutes les personnes travaillant sur celui-ci soient verrouillées sur les mêmes versions de dépendances.

S’il existe déjà un fichier poetry.lock ainsi qu’un fichier pyproject.toml, cela signifie soit que la commande d’installation a déjà été exécutée, soit que quelqu’un d’autre a exécuté la commande d’installation et validé le fichier poetry.lock sur le serveur de versioning.

Quoi qu’il en soit, l’exécution de l’installation, lorsqu’un fichier poetry.lock est présent, résout et installe toutes les dépendances répertoriées dans pyproject.toml, mais Poetry utilise les versions exactes répertoriées dans poetry.lock pour garantir que les versions du package sont cohérentes pour tous ceux qui travaillent sur le produit. Cela garantit que le produit ne se cassera pas à cause de changements inattendus dans les dépendances. Si le besoin apparait de mettre à jour les dépendances aux dernières versions, la commande poetry update peut s’en charger.

Bien que Poetry n’impose aucune règle de gestion des versions, il est fortement recommandé d’appliquer les règles proposées dans le Semantic Versioning.

Poetry possède plusieurs commandes pour interagir avec l’environnement de développement. Le but, ici, n’est pas de les détailler, mais voici la liste des principales commandes :

Interface ligne de commandes Poetry
Ligne de commandes Poetry

La structure de test Python a été mise en place automatiquement par Poetry. Le test proposé par défaut vérifie que la version du produit est bien égale à ‘0.1.0’ au moment de la création. Sur une version de Python supérieure à la 3.10, il est nécessaire d’installer une version plus récente de pytest (> 6.2.5). Pour ce faire, il suffit de modifier la version requise dans le fichier pyproject.toml à l’aide de la ligne pytest = "^7.1" et de relancer poetry update.

Lancer des tests revient à taper la commande pytest :

Poetry Pytest
Utilisation de pytest avec Poetry

Vous l’aurez sans doute deviné, Poetry est mon outil préféré pour les développement Python appliqués au NetDevOps.