Définition
Deux projets sur le même ordinateur, l'un qui réclame la version 2.20 d'une bibliothèque, l'autre la 2.31 : installées au même endroit, ces deux versions ne cohabitent pas, et la dernière arrivée casse le projet qui fonctionnait la veille. L'environnement virtuel existe pour ce problème précis.
C'est un dossier qui contient sa propre copie de l'interpréteur Python et son propre répertoire de paquets. Tant qu'il est activé, pip install écrit dedans, et import y cherche ses modules avant d'aller voir ailleurs. Le reste de la machine ignore son existence, et deux projets voisins gardent chacun sa version.
Trois commandes suffisent à en créer un et à s'y installer.
# Crée le dossier .venv à la racine du projet
python -m venv .venv
# Bascule ce terminal dans l'environnement
source .venv/bin/activate
# Installe requests dedans, et nulle part ailleurs
pip install requestsActiver ne fait rien de magique : le dossier passe en tête du chemin de recherche, et pour ce terminal seulement.
Sur Windows, l'activation s'écrit .venv\Scripts\activate. Le nom du dossier est libre, mais .venv s'est imposé : les éditeurs le repèrent seuls et les fichiers d'exclusion de Git le connaissent déjà.
Le problème qu'il résout
Sans lui, tout s'installe au même endroit : le répertoire de paquets de l'installation Python du système, partagé par tous les projets de la machine. Une seule version de chaque bibliothèque y tient à la fois.
Et cette version revient au dernier qui installe. Mettre à jour requests pour le projet du jour la met à jour pour tous, si bien que le projet écrit six mois plus tôt hérite d'une bibliothèque qu'il n'a jamais vue. Rien ne prévient, et la panne surgit trop loin de sa cause pour qu'on l'y relie.
Les deux situations se comparent sur quatre points, et le plus important n'est pas le premier.
| Sans environnement virtuel | Avec |
|---|---|
| Une seule version de chaque bibliothèque | Une version par projet |
| Les dépendances réelles du projet restent floues | Le dossier les liste exactement |
| Une installation peut casser un projet voisin | Le rayon d'action se limite au dossier |
| La machine du collègue ne reproduit pas la même chose | Un requirements.txt suffit à la reconstituer |
Le deuxième point pèse autant que le premier : un projet dont les dépendances vivent dans l'installation générale emprunte tôt ou tard un package installé pour tout autre chose, sans que personne le remarque. Il tourne là où il a été écrit, et manque à l'appel le jour du déploiement. Un environnement virtuel ne fait donc pas qu'isoler, il révèle.
Sur beaucoup de systèmes récents, pip refuse même d'installer hors d'un environnement virtuel et répond externally-managed-environment. Ce n'est pas une panne : c'est l'installation du système qui se protège.
Ce qu'il n'isole pas
C'est de là que viennent la plupart des déceptions : le mot « environnement » promet plus qu'il ne livre. Un environnement virtuel isole les paquets Python, et rien d'autre.
Il ne fige pas la version du langage : elle est héritée de l'interpréteur qui a servi à le créer, que le dossier désigne sans le contenir. Une mise à jour du système peut donc le rendre inutilisable du jour au lendemain, et la seule issue est de le recréer.
Il n'embarque pas non plus les bibliothèques système dont dépendent certains paquets compilés, ni les variables d'environnement, ni la base de données. Faut-il alors passer à Docker ? Non : un environnement virtuel n'est pas un conteneur, il répond à la question plus étroite des dépendances déclarées sur PyPI, pour un coût proche de zéro.
L'erreur classique de ceux qui le découvrent
Le symptôme est toujours le même : une ModuleNotFoundError sur une bibliothèque installée cinq minutes plus tôt. Elle est bien quelque part sur le disque, mais pas là où le programme la cherche.
Deux gestes produisent ce résultat. Installer sans avoir activé, et le paquet part dans l'installation générale. Activer dans un terminal puis lancer le programme depuis un autre, et la seconde fenêtre ignore tout de l'environnement.
Deux commandes tranchent la question sans avoir à deviner.
# Quel interpréteur ce terminal utilise-t-il ?
which python
# Et à quel Python ce pip est-il rattaché ?
pip -VSi les chemins affichés ne passent pas par le dossier du projet, l'environnement n'est pas actif. Un cas déroute plus longtemps : les éditeurs ont leur propre réglage d'interpréteur, et un script lancé depuis l'éditeur peut ignorer l'environnement activé dans le terminal d'à côté.
Ce qui se partage, ce qui se jette
Un environnement virtuel ne se déplace pas, il se reconstruit : les chemins écrits à l'intérieur sont absolus et désignent une machine précise.
Renommer ou déplacer le dossier du projet suffit à casser l'environnement qu'il contient : les scripts d'activation pointent toujours vers l'ancien chemin, et l'erreur affichée n'en dit rien. Supprimez le dossier et recréez-le.
Pour la même raison, verser un environnement virtuel dans Git est une fausse bonne idée : il pèse lourd et ne fonctionnera chez personne d'autre. Ce qui voyage, c'est la liste des paquets installés.
# Sur votre machine : noter les paquets installés
pip freeze > requirements.txt
# Sur une autre machine : reconstruire à l'identique
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtpip freeze relève tout ce qui est présent, dépendances de vos dépendances comprises, avec leur version exacte. Deux machines qui partent du même requirements.txt obtiennent le même jeu de bibliothèques, et un environnement abîmé cesse d'être un incident : il se supprime et se recrée sans rien perdre.
venv, virtualenv, Poetry, conda
Plusieurs outils répondent au même besoin. La bonne question n'est pas lequel est le meilleur, mais lequel apporte quelque chose que votre projet réclame vraiment.
| Outil | Ce qui le distingue |
|---|---|
| venv | Livré avec Python, décrit par la PEP 405, suffisant dans la grande majorité des cas |
| virtualenv | L'ancêtre externe, plus rapide et compatible avec de vieilles versions du langage |
| poetry | Gère l'environnement et le verrouillage des versions dans un seul outil |
| conda | Installe aussi des dépendances hors Python, courant en calcul scientifique |
Commencer par venv reste le bon réflexe : il est déjà là, et changer d'outil plus tard coûte peu, puisque la liste des dépendances, elle, se transporte.
Questions fréquentes
Faut-il un environnement virtuel pour un script de dix lignes ?
Si le script n'utilise que la bibliothèque standard, il n'y a rien à isoler et la réponse est non. Elle devient oui dès la première commande pip install : ce paquet s'installe quelque part, et ce quelque part servira aussi à tous les projets suivants.
Que faire quand l'environnement semble cassé ?
Le supprimer, puis le recréer à partir du fichier requirements.txt. C'est un dossier jetable, et une réinstallation propre règle la moitié des problèmes de dépendances plus vite que le moindre diagnostic.
Un environnement par projet, ou un seul pour toute la machine ?
Un par projet, faute de quoi le problème d'origine revient intact. Seule exception raisonnable : les outils en ligne de commande employés partout, comme ruff ou un formateur de code, qui ne dépendent d'aucun projet et gagnent à être installés à part, avec pipx.