Pipenv : Pourquoi faire ?

Hello tout le monde,

je découvre aujourd’hui, via le Pycoders Weekly, le projet pipenv, qui est présenté ici comme l’outil de gestion de packages officiellement recommandé.

Un peu surpris, et en parcourant rapidement quelques pages de docs, je lis, sur la doc officielle :

While pip alone is often sufficient for personal use, Pipenv is recommended for collaborative projects as it’s a higher-level tool that simplifies dependency management for common use cases.

En regardant un peu ce que ça fait, j’ai l’impression d’y voir une philosophie très proche de npm : un gestionnaire de dépendance de projet, qui vient tirer des dépendances locales.

Node et Python ont pourtant une différence de paradigme fondamentale concernant les environnements. Là où Python va installer les librairies au niveau du système, en utilisant le PYTHONPATH pour retrouver ses petits, node, de part l’historique du langage, va par défaut télécharger les dépendances dans le répertoire courant (le fameux node_modules) à moins qu’on l’invite à installer un package de manière global, dans le but d’utiliser une application au niveau système, sans que ça ait rapport avec un projet (newman, vue-ui, etc).

Les environnements virtuels de python ont beau ressembler à un répertoire node_modules, ce n’est pas du tout le même concept, puisque le principe consiste peu ou prou à tricher sur les variables d’environnements pour installer les dépendances à un autre endroit sur le système.

Et par là même, ça ne remplit pas le même rôle. Virtualenv crée des environnements python différents, avec son propre interpréteur, ses propres librairies.
Le fonctionnement de pip n’est pas affecté par virtualenv, il fonctionne comme il le ferait en “global”, il n’a pas conscience d’être dans un virtualenv.

Et ça permet du coup de faire des choses super intéressantes, avec des environnements contextuels, qui, du coup, ne se contentent pas de simplement décrire les dépendances de mon petit projet Django, mais peuvent aussi préparer et documenter (un minimum) l’environnement python dans lequel on va se trouver. Dans les faits, on voit souvent des projets avec ces niveaux de dépendances :

  • requirements/base.py
  • requirements/dev.py
  • requirements/jenkins.py
  • requirements/prod.py
  • requirements/doc.py

avec l’environnement de développement qui tire les dépendances de base et de la doc, l’env de prod qui vient tirer du gunicorn et d’autres paquets dont on a pas besoin à la maison, l’environnement jenkins qui va aussi tirer la doc, etc.

Beaucoup de souplesse, qu’on ne retrouve pas avec pipenv, puisqu’il semble qu’il n’y ait que des dépendances générales et des dépendances de dev. C’est un peu léger et surtout ça ressemble comme deux gouttes d’eau à ce qu’on voit côté npm.

J’ai spontanément quelques questions sur le sujet :

  • Quels sont les problèmes rencontrés avec une utilisation de pip (dans un virtualenv ou non) que pipenv se propose de régler ?
  • J’ai vraiment le sentiment que c’est pour coller à ce qui se fait ailleurs, indépendamment des spécificités du fonctionnement du langage. Est-ce que ce n’est pas faire une erreur de vouloir reproduire ce qui se fait chez node alors que la gestion de l’installation des librairies est vraiment différente ? C’est pour rendre l’explication des dépendances dans python plus compréhensibles pour des développeurs qui travaillent moins proche du système et qui ont des habitudes ailleurs ?
  • Est-ce qu’il n’y a pas un distinguo à apporter entre package manager, gestionnaire d’environnement, et gestionnaire de dépendance projet ?
  • Comment est-ce que pipenv va me rendre plus heureux, alors que finalement je n’ai jamais eu aucune douleur à utiliser pip et les virtualenv ces 10 dernières années ?
1 « J'aime »

Bonjour!

C’est surtout la gestion des dépendances secondaires : les dépendances des packages installés, par exemple werkzeug avec flask. Pipenv permet de définir les dépendances directes dans un pipfile et génerer un .lock file pour figer les dépendances secondaires et de garder le lockfile á jour lorsqu’on ajoute ou enleve de dépendances au projet. Si t’es á l’aise avec ton workflow pour cela ou tu ne resens pas le besoin de spécifier la version + hash des dépendances secondaires je pense que pipenv/poetry n’est pas pour toi…

1 « J'aime »

TL;DR: Je pense que pipenv a commencé comme une implèm de démo de la spec Pipfile (qui prédate pipenv).

Personnellement j’évite les outils “qui-font-tout-c-magique-tkt”, je préfère les outils “qui ne font qu’une chose mais qui le font bien”, ma stack actuelle se compose donc de :

  • setuptools pour packager (setup.cfg et un pyproject.toml, j’espère dans le futur pouvoir me passer de setup.cfg et d’écrire directement dans pyproject.toml.)
  • Des venvs, un par projet, j’ai même un alias bash de 6 lignes pour ça
  • pip

Et non, rien pour épingler mes dépendances, je pense qu’épingler les dépendances (et leurs sous dépendances) est un mensonge, pour plusieurs raisons :

  • Il n’existe pas forcément un ensemble de dépendances compatibles avec les versions de Python avec lesquelles votre projet est compatible.
  • Ça rend le projet incompatible avec les autres (si j’épingle numpy==1.22.1 et que quelqu’un épingle numpy==1.22.0 on ne peut pas installer nos deux projets ensembles).
  • Épingler implique souvent de prendre du retard sur les mises à jour (niveau sécurité c’est une mauvaise idée, on apprend aux gens à mettre à jour régulièrement, c’est pas pour leur fournir de vieilles dépendances).
  • Avoir la CI qui passe parce qu’on utilise un vieux pylint c’est joli, c’est green, mais mettre à jour pylint et se rendre compte que la nouvelle version trouve d’autres vrais bugs, c’est mieux.
  • Avoir la CI qui foire du jour au lendemain à cause d’un bug trouvé par une nouvelle version de pylint ou de mypy ou autre c’est inconfortable mais préférable à l’alternative (laisser un utilisateur final trouver le bug).

Je pense qu’il est préférable de tester différentes versions de nos dépendances dans la CI, pour s’assurer, un peu, qu’on ne ment pas dans le install_requires (qui devrait préciser la version minimale des dépendances, et éventuellement maximale (la prochaine release majeure d’une dépendance utilisant semver est probablement à exclure d’office, je préfère la tester moi-même avant de “relâcher” la contrainte dans install_requires, plutôt que laisser tester ça aux utilisateurs, c’est ce que j’expérimente dans oeis.

Mais pour les cas où on voudrait vraiment épingler, il existe un outil qui ne fait que ça mais qui le fait bien, pip-compile.

Et pour la prod je comprends qu’on puisse vouloir épingler dépendances et sous-dépendances, mais ce n’est pas le boulot du dev, c’est le boulot de celui qui s’occupe de la mise en prod, à lui de versionner un requirements.txt pour le projet qu’il utilise, où il veut (avec ses playbooks Ansible ou autre), et comme il veut. Il n’est même pas obligé de suivre le rythme de release du projet qu’il met en prod, et bonus il peut épingler pour la version de Python qu’il a en prod.

4 « J'aime »

J’ai passé ma journée à débogguer une erreur en production liée a une mise a jour numpy / numba - va peut-être falloir que je pin mes dépendances et que je teste pipenv :wink:

Oui du point de vue mise en production ce serait même une bonne pratique que tu saches précisément quelles versions des dépendances tu installes, mais ça n’est pas lié au code de ton programme en lui-même qui lui doit être prévu pour fonctionner avec le plus de versions possibles.

2 « J'aime »

J’ai testé pipenv, et maintenant je teste poetry.

Un seul outil chargé de résoudre des problèmes proches, a mon sens ça mène plus de confort.

Ça peut être un culte du cargo, cela dit pour un sous-ensembles des besoins, pipenv et poetry marchent bien.

C’est en effet, la séparation des responsabilités kivabien, mais ça n’empêche qu’avoir un outil dédié qui optimise l’expérience de développement pour les cas les plus courants: c’est bien.

C’est une bonne idée de tester d’autres choses, et potentiellement des nouveaux outils, on apprend toujours.

Il y a bien sur des alternatives, mais les commandes que j’utilise le plus souvent c’est:

  • poetry shell, alternative a pew;

  • poetry install qui permette d’installer une dépendances, avec le support de --dev; Tache qui est plus fastidieuse avec pip et pip-tools.

J’utilise moins souvent, mais ça correspond a mes attentes poetry publish qui permet de publier un package sur pypi.

Si je me souviens bien (j’ai oublié de prendre des notes :grimacing:) j’ai laissé tomber pipenv car je n’arrivais pas a construire un projet qui utilise cffi.

(Les outils c’est pas comme les anneaux, les gens trouvent leur comptent dans des outils différents pour différentes raisons car ils ont des besoins, des objectifs et des habitudes qui varient.)

1 « J'aime »