Cette dépêche est la suite d’une série sur Python initiée en septembre 2019. Après un sommeil cryogénique de un an et demi, on repart en forme avec d’autres contenus Python à vous proposer: actualité, bonnes pratiques, astuces, témoignages…
Cette sixième partie explique les inconvénients de pip
et présente l’alternative pipx
, le tout avec plein d’astuces et de conseils pour bien s’en sortir. 🚀 🐍
Pour rappel, les dépêches précédentes :
- Python — partie 1 parlait de la popularité explosive du langage Python
- Python — partie 2 évoquait la fin du support de Python 2
- Python — partie 3 parlait des différentes façons d’installer Python et des gestionnaires de paquets Python
-
Python — partie 4 vous présentait
py
etpyenv
pour faciliter la gestion de plusieurs versions de Python en parallèle sur un poste - Python — partie 5 vous faisait découvrir un autre moyen de gérer l’installation en parallèle de différentes versions de Python
Sommaire
- La problématique de l’installation des paquets Python
-
La bonne façon d’utiliser
pip
- Mettre à jour les paquets Python
- Environnement Python virtualisé
pipx
pour ne plus utiliserpip
- Tes astuces ?
- Licence
La problématique de l’installation des paquets Python
Le gestionnaire de paquets des distributions GNU/Linux
Les distributions GNU/Linux fournissent des applications et bibliothèques Python. Les intégrateurs de ces paquets font très attention à la cohérence et la compatibilité entre les dépendances communes à toutes ces applications. Les dépendances et applications sont fournies, le plus souvent, dans des paquets séparés. De plus, les intégrateurs prennent en compte certains correctifs, notamment celles concernant les failles de sécurité. Nous avons donc des paquets Python compatibles entre eux, sans faille de sécurité, et dont la mise à jour est gérée automatiquement par le système.
Par contre, ces paquets sont bien souvent dans une seule version, et pas forcément dans la version la plus récente. Un autre inconvénient est le nombre limité de paquets Python disponibles via la distribution GNU/Linux.
C’est pour cela, que nous utilisons pip
: pouvoir choisir la version exacte d’un paquet Python, et bien souvent la toute dernière version (voire une pré-version (pre-release)) ou pour installer des paquets Python qui ne sont pas fournis par votre distribution.
Le gestionnaire de paquets pip
L’outil pip
permet d’installer et de gérer des paquets Python directement en liaison avec le Python Package Index, dépôt qui rend ceux-ci accessibles à tout le monde via l’Internet.
Mais pip
n’empêche pas d’installer des dépendances dans des versions incompatibles avec d’autres applications. Et cela nous arrive de temps en temps de casser une application :-( !
La bonne façon d’utiliser pip
Généralement, la documentation dit d’installer avec :
pip install nom_paquet
Comme on rencontre un problème de permission, on commence à vouloir bien faire avec :
sudo pip install "nom-du-module-python" # en root
Ce qui rentre en conflit avec :
sudo apt install "autre-nom-du-meme-module-python"
sudo dnf install "autre-nom-du-meme-module-python"
sudo yum install "autre-nom-du-meme-module-python"
Pour éviter que pip
(et pip3
) écrase les fichiers installés par apt
, sur Debian les deux installations sont séparées :
-
/usr/lib/python2.7/dist-packages
avecapt
-
/usr/local/lib/python2.7/dist-packages
avecpip
Comme Python est très souvent utilisé par des outils de maintenance ou d’administration des machines, cela peut créer des problèmes : installation de versions de certains paquets directement à la place de ceux du système, ou encore installation de certains paquets pour l’utilisateur qui ont la priorité par rapport aux versions installées par le système. Il est très fortement conseillé d’utiliser des environnements virtuels . Il est fortement déconseillé d’installer un paquet via pip
dans le cadre d’une commande sudo
(le meilleur moyen de casser votre système).
Le pire, c’est de mettre à jour pip
avec lui-même, car pip
nous le réclame : pip install --upgrade pip
et cela a quelquefois comme conséquence de casser pip
! Installer des modules Python devient un bazar si on ne prend pas les bonnes pratiques dès le début.
Cette problématique est très fréquente comme nous pouvons le constater sur le ticket #5599 du projet pip
.
Bonnes pratiques :
- Ne jamais utiliser
sudo pip
car la gestion des paquets (et des modules Python) du système est gérée parapt
,yum
,dnf
… - Utiliser
pip install --user
pour installer des modules pour son besoin personnel sans écraser les modules Python du système ; - Ne pas utiliser
pip install
(même avec--user
)
Les pratiques n°2 et n°3 rentrant en conflit, bien réfléchir avant d’installer un module Python avec pip
. Est-ce que le module peut être installé avec apt
, yum
, dnf
? De quelle version avons-nous besoin ? Et pourquoi pas un environnement Python virtualisé ? Et un conteneur ?…
Bon, revenons à pip
, supposons que nous décidions d’appliquer la pratique n°2 et de ne pas écouter la pratique n°3. Nous allons donc installer notre module en précisant toujours l’argument --user
:
pip install "nom-du-module-python" --user
Attention, notre pip
utilise peut-être Python 2, voici une meilleure ligne de commande :
pip3 install "nom-du-module-python" --user
Attention, nous pourrions avoir plusieurs versions Python 3 installées sur notre machine.
Voici une encore meilleure ligne de commande :
python3 -m pip install "nom-du-module-python" --user
Pour la différence entre pip3
et python3 -m pip
lire les détails sur stackoverflow (en anglais). En bref, on est sûr que python3 -m pip
utilise la même arborescence d’installation que le script qui est exécuté avec python3 « nom-du-script.py"
(ou #!/usr/bin/env python3
). C’est d’autant plus recommandé si le $PATH
de la machine est tarabiscoté, s’il y a plusieurs installations de Python sur l’ordinateur ou encore que la machine soit sous Windows.
Et si nous voulions préciser l’installation Python avec laquelle nous souhaitons travailler :
/chemin/vers/bin/python3 -m pip install "nom-du-module-python" --user
Attention, si nous avions une ancienne version du module python déjà installée sur notre machine, les commandes pip
ci-dessus ne nous permettent pas d’installer la dernière version du module Python :-/
Ajoutons l’argument --upgrade
:
python3 -m pip install "nom-du-module-python" --user --upgrade
Nous pouvons aussi changer la barre de progression :
python3 -m pip install "nom-du-module-python" --user --upgrade --progress-bar emoji
Et pour utiliser le module Python fraichement installé :
python3 -m "nom-du-module-python" [options du module]
Oui, cela devient compliqué ! Mais cette façon de faire, avec malheureusement de longues lignes de commande, va nous éviter bien des problèmes.
De plus, même en appliquant les recommandations 2 ou 3, si on installe un paquet pour utilisation avec le Python 3 standard de la machine, ceci peut casser le fonctionnement de certains programmes (le paquet ainsi installé étant prioritaire par rapport à celui du système, s’il y a des incompatibilités… boum). La bonne façon de faire est d'utiliser des environnements virtuels (où l’on peut utiliser directement pip
sans risque). C’est une bonne pratique à adopter dès le début afin de s’éviter des problèmes ultérieurs. Cf la suite de la dépêche et la dépêche suivante sur Python où nous vous parlerons plus en détails des environnements virtuels.
Sous Anaconda ou Miniconda avec conda
La société Continuum Analytics qui réalise ces distributions Python fournit des paquets déjà compilés pour de nombreuses bibliothèques Python (et autres langages), principalement dans le domaine des sciences et du calcul mais pas uniquement. Certaines de ces bibliothèques ne sont pas toujours triviales à reconstruire, particulièrement sous Windows. L’adoption d’Anaconda peut être une solution si l’installation de certains paquets échoue avec d'autres distributions.
Attention toutefois avec Anaconda ou Miniconda : ils ont tendance à être très gourmands en espace disque (on arrive assez rapidement à des Gio occupés).
Note : Sous Windows un menu d’application Anaconda Prompt est ajouté dans le groupe de programmes Anaconda. Il permet d’accéder à conda
même si celui-ci n’est pas accessible dans les répertoires du PATH
.
Conda gère un environnement base, celui par défaut correspondant à son installation de Python, mais peut aussi gérer des environnements supplémentaires avec leurs propres installations de Python et des paquets (avec les versions au choix).
~$ conda activate base
(base) ~$ which python
/home/login/.miniconda3/bin/python
(base) ~$ conda install numpy
…(liste de paquets à installer/mettre à jour)…
Proceed ([y]/n)? y
…(téléchargement puis installation)…
Lorsqu’un paquet n’est pas disponible dans les dépôts de conda, on peut l’installer simplement à partir de PyPI avec pip
. Il faut juste prendre soin de lancer pip pour le Python fourni par conda :
(base)~$ conda install osc4py3
…
PackagesNotFoundError: The following packages are not available from current channels:
- osc4py3
…
(base)~$ python -m pip install osc4py3
(base)~$ python
Python 3.6.9 |Anaconda, Inc.| (default, Jul 30 2019, 19:07:31)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import osc4py3
>>>
À noter : certains IDE comme Pyzo donnent directement accès aux commandes conda
et pip
dans leur fenêtre de shell Python.
Mettre à jour les paquets Python
Avec le gestionnaire de paquets
Les paquets installés avec les gestionnaires habituels sous Linux (apt
, yum
, dnf
…) peuvent être mis à jours simplement avec ces mêmes gestionnaires. Ceux-ci assurent la cohérence des versions installées (et il vaut mieux ne pas interférer avec ce qu’ils installent).
Voir pour chaque gestionnaire de paquets sa documentation pour faire des mises à jour système.
Avec pip
On a vu qu’il était possible avec pip
de mettre à jour un paquet particulier avec l'option --upgrade
:
/chemin/vers/python -m pip install nom_du_paquet --user --upgrade
Mais il n’y a pas pour le moment de mise à jour automatique simple de l’ensemble des paquets installés avec pip. Celui-ci propose seulement un argument --outdated
pour lister les paquets obsolètes. Avec un shell, en l’intégrant dans une expression en ligne de commande, il est toutefois possible de réaliser cette tâche :
/chemin/vers/python -m pip list --user --outdated --format freeze |
cut -d= -f1 |
xargs --no-run-if-empty /chemin/vers/python -m pip install --user --upgrade --progress-bar emoji
Sous macOS, il faut retirer l’argument --no-run-if-empty
de l’exemple ci-dessus.
Notons que de nombreuses applications système sont codées en Python. Mettre à jour les modules et leurs dépendances même avec l’argument --user
peut changer le comportement des applications exécutées par l’utilisateur. Par exemple, si nous utilisons meld
en ligne de commande pour comparer deux fichiers, meld
pourrait ne plus fonctionner correctement. C’est qu’il fallait respecter la bonne pratique n°3 ! (lire aussi le commentaire de lolop)
Pour l’anecdote, un jour, Oliver décide de mettre à jour ses modules Python dont un module redis
qui avait été installé à partir d’un fichier requirements.txt
avec une version précise. Sans s’en rendre compte ce module passait de la version 2 à la version 3 avec une incompatibilité dans l’appel des fonctions. Benoît Sibaud a eu un souci similaire avec pyOpenssl en conflit avec la version fournie par le gestionnaire de paquets de la distrib. C’est à ce moment-là que l’on comprend pourquoi pip
ne permet pas de mettre à jour tous les modules d’un coup !
Si quelqu’un s’amuse à mettre à jour tous tes modules avec pip
, il serait prudent de prendre quand même des précautions comme enregistrer préalablement les versions des modules avant la mise à jour :
python3 -m pip list --user --format freeze > ~/requirements_avant_pip_upgrade.txt
python3 -m pip list --user --outdated --format freeze |
cut -d= -f1 |
xargs --no-run-if-empty python3 -m pip install --user --upgrade --progress-bar emoji
python3 -m pip list --user --format freeze > ~/requirements_apres_pip_upgrade.txt
Pour visualiser les changements :
sudo apt install meld
meld ~/requirements_avant_pip_upgrade.txt ~/requirements_apres_pip_upgrade.txt
En cas de problème, revenir aux versions précédentes :
python3 -m pip install --user -r ~/requirements_avant_pip_upgrade.txt
Avec Conda
Pour les paquets fournis via Anaconda ou Miniconda, une simple commande exécutée dans l’environnement conda activé permet d’effectuer les mises à jour dans cet environnement :
(base) ~$ conda update --all
…
Environnement Python virtualisé
Alors, utiliser pip
est dangereux ? Oui, sauf dans un environnement Python virtualisé. \o/
L’idée est d’avoir une installation des paquets Python spécifique pour chacun de ses projets, avec une maîtrise des versions et des dépendances, et qui n’interfère pas avec l’installation standard des paquets par le système. Et le tout versionné avec le code source de son projet. Ainsi nous avons une installation équivalente pour les différents développeurs et la production.
Quelques outils pour créer des environnements virtualisés :
-
python -m venv
fait partie des piles fournies avec Python ; -
virtualenv
est l’ancêtre devenv
mais il continue d’évoluer et il est bien plus utilisé quevenv
(article en français) ; -
virtualenvwrapper
est une série d’extensions pourvirtualenv
; -
pipenv
est une surcouche agréable au-dessus devirtualenv
et depip
; -
conda
gère aussi des environnements virtuels, et propose un certain nombre de bibliothèques pré-packagées en supplément àpip
; -
pipx
crée un environnement virtuel pour chaque programme Python du système, que l’on souhaite protéger d’un cassage accidentel par mise à jour des dépendances.
pipx
pour ne plus utiliser pip
Comme nous le disions, malgré tout le soin apporté à la préparation d’un paquet Python par un développeur et au contrôle soigné de ses dépendances, il arrive que nous cassions de façon incontrôlée des dépendances de paquets Python.
Le cas typique est par exemple un paquet fournissant un utilisateur en ligne de commande, disons supertoto
, qui dépend du paquet super
en version 1. Par la suite, vous installez un autre utilitaire, supertiti
, qui dépend aussi du paquet super
mais en version 3. Lors de l’installation de supertiti
, le paquet super
va être mis à jour vers la version 3, qui malheureusement n’est pas rétro-compatible avec la version 1. Vous venez de casser supertoto
.
Pour éviter ce type de problème d’interférence entre les différentes dépendances installées avec pip
, l’astuce est d’installer chaque application et ses dépendances dans un environnement isolé.
Et voilà, pipx
, une alternative à pip
, mais uniquement pour l’installation d’applications Python. Le gestionnaire de paquets pipx
n’a pas été conçu pour l’installation de bibliothèques Python (les dépendances).
L’outil pipx
installe chaque application dans un environnement virtuel avec venv
. Ainsi, plus de conflit entre les différents paquets applicatifs et leurs dépendances respectives, et donc plus besoin de s’embêter avec les environnements virtuels.
Quant à l’outil pip
, il peut être relégué à une seule utilisation : installer pipx
(un peu comme, sous Windows, le navigateur Explorer/Edge ayant pour seule utilité de télécharger Firefox). On peut aussi installer pipx
avec apt
/dnf
/nix-env
/… Les puristes considèrent même que pip
est volontairement dissocié de l’installation de Python pour permettre d’utiliser pipx
sans jamais devoir passer par pip
!
En fait, d’autres outils se basent sur pip
comme pipenv
, il vaut donc mieux garder un pip
fonctionnel sur son ordi. 😁 Les deux outils pip
et pipx
cohabitent très bien, chacun avec ses avantages. 👍
Installation avec pip
:
/usr/bin/python3 -m pip install --user --upgrade pipx
Le plus dur est de prendre l’habitude d’utiliser pipx
à la place de pip
. Allez, on commence par désinstaller les applications préalablement installées avec pip
:
/usr/bin/python3 -m pip uninstall black flake8 pipenv poetry meld
On résinstalle avec pipx
:
$ /usr/bin/python3 -m pipx install black
installed package black 19.3b0, Python 3.7.4
These apps are now globally available
- black
- blackd
done! ✨ 🌟 ✨
Il se souvient bien sûr que l’installation a déjà été faite :
$ /usr/bin/python3 -m pipx install black
'black' already seems to be installed. Not modifying existing installation in '/home/o/.local/pipx/venvs/black'. Pass '--force' to force installation.
D’autres utilitaires sympathiques en ligne de commande, à installer avec pipx :
$ /usr/bin/python3 -m pipx install pipenv
installed package pipenv 2018.11.26, Python 3.7.4
These apps are now globally available
- pipenv
- pipenv-resolver
done! ✨ 🌟 ✨
$ /usr/bin/python3 -m pipx install poetry
installed package poetry 0.12.17, Python 3.7.4
These apps are now globally available
- poetry
done! ✨ 🌟 ✨
$ /usr/bin/python3 -m pipx install flake8
installed package flake8 3.7.8, Python 3.7.4
These apps are now globally available
- flake8
done! ✨ 🌟 ✨
$ /usr/bin/python3 -m pipx install meld --include-deps
⚠️ File exists at /home/o/.local/bin/futurize and points to /home/o/.local/bin/futurize, not /home/o/.local/pipx/venvs/meld/bin/futurize. Not modifying.
⚠️ File exists at /home/o/.local/bin/pasteurize and points to /home/o/.local/bin/pasteurize, not /home/o/.local/pipx/venvs/meld/bin/pasteurize. Not modifying.
installed package meld 0.2.3, Python 3.7.4
These apps are now globally available
- f2py
- f2py3
- f2py3.7
done! ✨ 🌟 ✨
Notons l'option --include-deps
nécessaire pour installer meld
.
Tes astuces ?
N’hésite pas à partager tes expériences, tes astuces et tes interrogations.
Et un peu d’aide pour la rédaction de cette série est toujours la bienvenue. Les prochaines dépêches parleront de pipenv
, d’empaquetage, voire de tout autre sujet que tu pourrais nous amener pour en faire une dépêche. Viens faire un tour dans l’espace de rédaction!
Licence
Cette dépêche est publiée sous licence CC0 (en domaine public dans les pays où cela est possible) pour permettre de la recopier, modifier, réutiliser et republier sans obligation de citer ses auteurs. Sauf dans certains pays, comme la France, dont la loi oblige quand même à citer les auteurs. Au moins, cela montre l’intention des auteurs à autoriser le plagiat.
Aller plus loin
- Python — partie 1 ― Popularité (21 clics)
- Python — partie 2 ― Python 2 (10 clics)
- Python — partie 3 — Installation de Python et de paquets (16 clics)
- Python — partie 4 — Py Pyenv (18 clics)
- Python — partie 5 — Nix (et Guix) (29 clics)
- Python — partie 7 — Environnements virtuels (94 clics)
- Python— partie 8 — Pipenv (48 clics)
- Python ― partie 9 ― Formateur de code, analyse statique (42 clics)
- Python — partie 10 — Entretiens (9 clics)
# Pourquoi privilégier l'arborescence utilisateur pour les installations locales ?
Posté par Guillaume Rousse (site web personnel) . Évalué à 3.
Bonjour.
J'ai du mal à comprendre l'insistance dans la communauté python pour l'installation de modules supplémentaires dans l'arborescence d'un utilisateur spécifique, via l'option
--user
, au lieu de les installer sur le système, dans l'arborescence/usr/local
dédiée à cet usage, après escalade de privilèges. L'auteur commence d'ailleurs par expliquer que cette arborescence est déjà prête à l'usage dans le cas de Debian, en dans fait pour n'importe quelle autre distribution Linux. La seule justification que j'ai vu jusqu'ici, c'est qu'il s'agit d'une bonne pratique, alors que pour moi, c'est clairement:* ignorer les conventions d'administrations usuelles sous Linux
* privilégier un utilisateur particulier, ce qui a un sens sur une machine personnelle mono-utilisateur, pas sur un serveur géré par plusieurs personnes
* favoriser le déploiement d'une application s'exécutant avec le même compte utilisateur que celui qui possède les fichiers correspondant à celle-ci, donc mélanger privilèges d'exécution et d'écriture, une mauvaise pratique en terme de sécurité
Je comprendrais à la rigueur qu'on explique que Python n'étant pas spécifique à Unix, ses utilisateur privilégient l'utilisation de conventions facilement transposables d'un OS à l'autre. Ou encore que l'on dise que les risques d'interférence avec le système de base étant tellement élevés dans l'écosystème Python, qu'il mieux vaut ne surcharger les modules du système qu'à la demande, via des installations locales dans des répertoires qui ne sont pas pris en compte par défaut, mais uniquement via une variable d'environnement dédiée. Mais j'ai du mal avec l'argument d'autorité, même rebaptisé "bonne pratique (tm)".
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.