Patrice Ferlet
Patrice Ferlet
Créateur de ce blog.
Publié le juin 20, 2020 Temps de lecture: 8 min

Me suivre sur Mastodon

Passer De Pip À Pipenv

thumbnail for this post

La commande “pip” couplée à des virtualenv, c’est un peu le b.a.-ba en Python. Mais “pipenv” va vous rendre la vie encore plus facile.

Cela fait des années que je code en Python, depuis environ 2003 pour être exact. Je suis passé par pas mal de techniques pour éviter d’écrire mes dépendances dans le système, et il faut bien avouer que les Virtualenv ont beaucoup aidé l’adoption de Python. Ça, et l’avènement du Machine Learning dans lequel Python fait de plus en plus d’adpetes. Avant toute chose, je vais insister sur un truc qui m’énerve très souvent…

Arrêtez de faire des “sudo pip install truc” !!!

Cette commande installe les paquets (packages et modules) sur votre système, donc :

  • si un paquet de votre distribution (deb, rpm, etc…), contient cette dépendance, il va vous l’exploser
  • si vous avez deux projets / applications Python qui ont la même dépendance, mais pas avec la même version, vous allez en avoir une des deux qui va se vautrer
  • et puis mince à la fin, c’est quoi cette idée de faire des installations dans le système ?

Alors oui, on peut ajouter l’option --user qui va installer les packages et binaires dans votre HOME, c’est bien… Mais cela doit rester anecdotique, pour des outils dont le paquet n’existe pas sur votre distribution, ou si vous savez ce que vous faites. Dans tous les cas, pour développer en Python, on passe par un environnement virtuel.

Je vais donc vous faire un rappel, puis on parlera de Pipenv

Avant, on faisait des virtualenv et on utilisait “pip”

Avant de parler de Pipenv, je pense qu’il est important de voir comment la plupart des projets sont démarrés en Python avec pip et les virtualenv.

La méthode super standard aujourd’hui, qui marche très bien, c’est de créer un environnement virtuel.

mkdir -p ~/Projects/monsite1
cd ~/Projects/monsite1

python -m venv virtualenv

# et on doit activer cet environnement avant de bosser
# ... à chaque fois...
source vitrualenv/bin/activate

À partir de là, toutes les commandes pip install vont installer les packages et dépendances dans le répertoire virtualenv (vous pouvez le nommer autrement si ça vous chante) - c’est pratique, et quand on a l’habitude c’est quasiment un reflex.

Intéressant aussi, on peut taper cette commande pour générer un fichier de dépendances pour que vos collaborateurs puissent avoir la même version que vous :

pip freeze > requirements.txt

# vos collaborateurs vont ensuite faire:
pip install -r requirements.txt

C’est cool, mais ça a quelques inconvénients:

  • d’abord, il faut penser à créer le virtualenv sur les postes de vos collègues de projet
  • ensuite, le “freeze” colle les paquets + dépendances
  • et en plus de cela, si vous avez des packages / outils seulement pour le développement, et bien ils sont dans ce fichier…
  • et puis si on travaille avec git, il faut penser à “ignorer” le virtualenv (ou le placer en dehors du projet)

Donc, oui, ça marche bien, mais ça demande un peu de manipulation pour séparer ces fameuses dépendances de “dev”.

À côté de cela, on voit Node utiliser un “package.json” via npm, qui sait d’ailleurs très bien séparer les dépendances de dev et de run - ou encore “composer” pour PHP qui fait à peu près bien ce travail…

Sous Python, on se sentait un peu démunis, en dessous du lot, un peu peiné d’avoir un langage tellement cool mais avec une gestion de package limitée…

Et puis arrive le prince Pipenv !

Pipenv, mon ami mon frère

Depuis quelques mois, je teste “pipenv” - et je peux vous dire que j’ai du mal à comprendre pourquoi si peu de Pythonistes ne l’utilisent. Et surtout, pourquoi il n’est pas plus connu !? Car là, on a un outil propre, qui fait exactement ce dont on a toujours besoin en dev Python, qui reprend les concepts utiles de “npm”, “glide”, ou “composer”… Bref, un truc qui sert professionnellement !

Cette commande est dans la plupart des dépôts de distribution, donc dnf install pipenv, ou apt install pipenv fonctionnera. Dans “alpine”, pas le choix, on passera par “pip” pour l’installer avec pip install pipenv (c’est logique d’utiliser pip ici). OSX n’est pas en reste… Avec brew ça passe aussi.

Pipenv ne va pas vous éloigner de “pip”, en fait il est même simplement un genre de “superset” de cet outil. Vous allez voir, c’est vraiment le panard.

Créons un projet de site:

mkdir -p ~/Projects/monsite1
cd ~/Projects/monsite1

pipenv install

Et c’est tout.

Voilà… Croyez-le ou non, c’est déjà prêt. Il vient de faire le nécessaire;

  • création d’un virtualenv
  • préparation d’install de dépendances

Vous allez trouver deux fichiers, Pipfile et Pipfile.lock, l’un contient les dépendances, et le second va contenir les informations de version de tout ce que vous allez installer.

Déjà, il faut bien comprendre que le fichier “Pipfile” remplace (en quelque sorte) le fichier “requirements.txt”. Donc, quand un collaborateur va récupérer votre dépôt, il fera aussi un appel à la commande “pipenv install”, et cela installera les dépendances de projet.

On est clairment dans la même situation qu’avec package.json pour NPM, ou composer.json pour composer… Mais en Python !

Allons y, installons “Flask”:

pipenv install flask

Quoi ? Comme ça ? Sans activer de virtualenv ?

Et oui mes amis, le virtualenv a été créé par l’outil et il l’utilise tout seul. Mais il est où ce virtualenv ?

$ pipenv --venv
/home/metal3d/.local/share/virtualenvs/monsite2-EXci-bmn

Il le trouve comme un grand.

Pour que cet environment soit actif vous avez plusieurs solutions. La plus simple est d’utiliser la commande pipenv run [command] avec, bien entendu, la commande que vous voulez. Par exemple, pour lancer flask:

pipenv run flask run -h 0.0.0.0

Sinon, vous pouvez lancer un shell:

pipenv shell

Cette commande active le virtualenv. Alors important !!! évitez d’utiliser la commande deactivate et pressez plutôt CTRL+D pour désactiver le shell. Si vous vous plantez, c’est pas très grave : redémarrez votre terminal si vous avez des soucis.

Mais c’est pas fini !

Installons un outils de test unitaire, par exemple…“pytest”. On est d’accord que cet outil ne doit être installé que pour le développement ? En production, on en veut pas. Et bien, tout comme avec “npm”:

pipenv install pytest --dev

Et voilà, une dépendance installée pour les développeurs. Ce qui veut dire que :

# n'installe que les packages de run
pipenv install 

# install SANS METTRE À JOUR le fichier .lock
# (pour installer en prod)
pipenv sync

# pour avoir les outils de dev
pipenv install --dev

# et si on veut tout, en une fois :
pipenv install --all

Et attendez… C’est pas fini…

Vous voulez générer les fichiers de requirements, parce que votre environment de déploiement gère “pip”. Et bien, pas de souci, “pipenv” sait le créer en évitant les paquets de développements :

pipenv lock -r > requirements.txt

Et si vous voulez générer des requirements séparés :

pipenv lock -r --dev > requirements-all.txt
pipenv lock -r --dev-only > requirements-dev.txt

Le site propose une jolie animation:

Exemple de séquence Pipenv - source https://pipenv.pypa.io/en/latest/

Les petits trucs en plus

Un truc que j’apprécie énormément, c’est le fait de pouvoir utiliser un fichier .env. Très pratique avec Flask pour mettre “FLASK_DEBUG=1” par exemple. Et bien entendu, ces variables sont chargées en tant que variable d’environnement (le nom aurait dû vous orienter) :

$ echo "FOO=bar" > .env
$ pipenv run python -c "import os; print(os.environ['FOO'])"
Loading .env environment variables…
bar

Si vous voulez avoir l’arbre de dépendance, c’est aussi très pratique à lire :

$ pipenv graph
MarkupSafe==1.1.1
pytest==5.4.3
  - attrs [required: >=17.4.0, installed: ?]
  - more-itertools [required: >=4.0.0, installed: 8.4.0]
  - packaging [required: Any, installed: 20.1]
  - pluggy [required: >=0.12,<1.0, installed: 0.13.1]
  - py [required: >=1.5.0, installed: 1.8.2]
  - wcwidth [required: Any, installed: 0.2.3]

Pour parfaire le tout, pipenv propose de la completion, dans votre ~/.bashrc, ajoutez :

source <(pipenv --completion)

Et le tour est joué.

Et il y a bien d’autres options, comme “check” qui vérifie les requirements “PEP 508”. La documentation est simple mais efficace. La page PIpenv Advance Usage est une mine d’informations.

Et vous pouvez même tester en ligne l’outil sans rien installer chez vous 🎉

En bref

En gros, je ne me sers plus vraiment de “pip”. Pipenv a pris le relais. Mon process est clairement plus souple. J’ouvre vim avec la commande pipenv run vim pour avoir le contexte de virtualenv dans l’éditeur.

Notez que VSCode, vscodium1, Pycharms, etc… savent utiliser pipenv.

Je génère tout de même les fichiers de requirements pour installations plus anciennes, et/ou pour le déploiement (car “pip” est plus répandu sur les plateformes de déploiement), mais je les génère plus proprement avec “pipenv” qui évite les packages de dev.

Pipenv ne change pas radicalement votre workflow, il vous évite simplement certains init, des commandes superflues, et une gestion de dépendances manuelle. En soit, les deux seules commandes utiles pour démarrer sont :

  • pipenv install ... [--dev] pour créer, installer le projet, en séparant ou non les paquets de dev
  • pipenv run <command> pour lancer une commande avec l’environnement virtuel activé

Eventuellement, ponctuellement, pipenv uninstall, pipenv lock -r

En gros, pipenv est un bel équivalent de “npm” mais pour Python. Je vous conseille vraiment de tester. N’hésitez pas à commenter, partager l’article et discuter avec moi de ces sujets 👍


  1. vscodium est un build de VSCode qui n’envoit pas de données à Microsoft ↩︎

comments powered by Disqus