PEP 668 : error: externally-managed-environment

On discute ce matin sur #python-fr sur IRC de la bientôt fameuse « erreur : externally-managed-environment ».

Derrière tout ça, il y a la PEP 668.

TL;DR

Si

$ python3 -c 'print(__import__("sysconfig").get_path("stdlib", __import__("sysconfig").get_default_scheme()))'

te donne un dossier qui contient un fichier EXTERNALLY-MANAGED, alors il est interdit d’utiliser pip avec cet interpréteur, (pour installer il faut donc passer par le gestionnaire de paquets de sa distrib).

Pourquoi ?

Parce qu’utiliser deux gestionnaires de paquets en même temps est un aimant à bugs, le plus méchant pouvant rendre le gestionnaire de paquet de votre distrib inutilisable, une situation inextricable.

Alors, comment on fait ?

On utilise le gestionnaire de paquet de son système d’exploitation, à la place de pip install django on apt install python3-django sur Debian par exemple.

On peut aussi utiliser des venv, la règle ne s’applique pas dans les venvs :

$ python3 -m venv .venv
$ source .venv/bin/activate
$ python -m pip install django
Collecting django
  Downloading Django-4.1.7-py3-none-any.whl (8.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.1/8.1 MB 3.4 MB/s eta 0:00:00
Collecting asgiref<4,>=3.5.2
  Using cached asgiref-3.6.0-py3-none-any.whl (23 kB)
Collecting sqlparse>=0.2.2
  Using cached sqlparse-0.4.3-py3-none-any.whl (42 kB)
Installing collected packages: sqlparse, asgiref, django
Successfully installed asgiref-3.6.0 django-4.1.7 sqlparse-0.4.3

Et sudo pip install ?

J’espère que tu n’utilisais pas sudo pip install, c’était déjà un aimant à problèmes, maintenant c’est terminé.

J’ai qu’à sudo rm /usr/lib/python3.11/EXTERNALLY-MANAGED donc ?

C’est un garde-fou, le déboulonner ne me semble pas sage. As-tu déjà eu l’idée de déboulonner le garde-fou de ton balcon « parce qu’il te gêne » ? Peut-être, mais tu ne l’as pas fait, c’est sage.

Mais j’ai compilé mon Python !

Si, comme moi tu aimes compiler ton propre Python pour en avoir plein, il te suffit de ne pas aller volontairement mettre un fichier EXTERNALLY-MANAGED à la racine de la stdlib de ton Python à toi, et tu gardes le droit d’installer, facile :

$ ~/.local/bin/python3.11 -m pip install django
Collecting django
  Using cached Django-4.1.7-py3-none-any.whl (8.1 MB)
Collecting asgiref<4,>=3.5.2
  Using cached asgiref-3.6.0-py3-none-any.whl (23 kB)
Collecting sqlparse>=0.2.2
  Using cached sqlparse-0.4.3-py3-none-any.whl (42 kB)
Installing collected packages: sqlparse, asgiref, django
Successfully installed asgiref-3.6.0 django-4.1.7 sqlparse-0.4.3

À toi de voir si tu préfères avoir ton Python ou le Python de ta distrib en premier dans ton PATH, certains vont préférer :

PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/$HOME/.local/bin

quand d’autres vont préférer :

PATH=/home/$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

dans le premier cas python, python3 python3.11 sont ceux de votre distrib’, utilisez le gestionnaire de paquets de votre distrib pour leur installer des paquets.

dans le second cas python, python3 python3.11 sont ceux que vous avez compilés, utilisez pip.

Conclusion

Avant, chez moi, la frontière entre le Python de ma distrib et le Python de même version compilé maison, était floue : je pouvais utiliser /usr/bin/python3.11 pour installer dans ~/.local/lib/python3.11, ça se mélangeait un peu les pinceaux.

Maintenant c’est super clair :

  • ~/.local/bin/python3.11 -m pip fait ses installations dans ~/.local/lib/python3.11/, et uniquement ici.
  • /usr/bin/python3.11 ne reçois de paquets Python que de ma distrib.

Chacun chez soi et les serpents seront bien gardés !

2 « J'aime »