PDM + uv, duo de choc pour vos projets Python

J'ai aimé pipenv, j'ai aimé poetry, mais là... mon coeur a été conquis par PDM et Uv. Découvrez pourquoi cette combinaison est devenu mon choix pour gérer mes projets Python.
Si vous êtes un développeur Python, et que vous travailez avec des environnements virtuels et la gestion des dépendances, vous avez probablement entendu parler de pipenv et poetry.
Le principe reste le même : un outil pour gérer les dépendances, créer des environnements virtuels, et faciliter la
gestion d’un projet Python. Aussi, ces outils permettent de construire et pousser les paquets sur PyPI. Moins de galère
qu’un setup.py
, plus sécurisant en terme de “lock” de version. Tout le monde est content. Ou pas…
Vous allez vite comprendre de quoi je parle, et je vais vous faire un topo des trucs lourdingues avant de vous parler de
uv
et de pdm
. Mais si vous êtes pressé, un “too long; didn’t read” ça fait gagner du temps.
TL;DR
Ce que vous allez gagner :
Gain de place drastique sur le disque, résolution de dépendances très rapide grâce à
uv
et un excellent support pour les CI (build, test) et CD (publish avec gestion OIDC vers Gitlab par exemple)
Installez “uv” et “pdm”, personnellement j’utilise homebrew
sur Linux:
brew install uv pdm
Sinon, uv
est dans les paquets de Fedora. Pour pdm, allez voir la doc d’installation pour toutes les options (pipx, pip, usr, etc.).
Puis :
pdm config use_uv true
Créez votre projet avec :
pdm init
Et vous pouvez installer les dépendances avec :
pdm add package1 package2 # pour les dépendances normales
pdm add --group devel package3 # pour les dépendances de dev
pdm run python script.py # pour lancer un script dans l'env virtuel
pdm build # crée un paquet python
pdm publish # pousse le paquet sur PyPI
Vous aurez un cache d’installation globale, donc aucune réplication de paquets, les paquets sont liés avec des liens hard (hard links). C’est super rapide, et la création de paquets est très simple.
PDM permet de pousser vos paquets sur PyPI, et gère les scripts, les dépendances de développement, etc. C’est poetry
mais dopé comme un coureur du tour de France.
pip, puis poetry
Qu’on se le dise, “pip
” est l’outil “legacy”, le vieux pépère qui accompagne Python pour installer des paquets. Il
fonctionne, il fait le job, et il sera toujours présent. Sauf que voilà… très vite vous vous prenez au jeu, vous
faites des environnements virtuels, vous gérez des dépendances, et là, “pip
” devient vite limité. Si si, soyon
honnêtes, avoir un fichier de “requirements.txt” ça devient vite l’enfer. Outre la gestion de versions, quand vous
voulez séaprer les dépendances de développement, de production, etc. Vous avez l’impression de bricoler.
Avant, on faisait ce genre de sorcellerie :
python -m venv .venv
source .venv/bin/activate
pip install flask
pip freeze > requirements.txt
Et on était content hein, on donnait ça à manger à nos collègues, et tout le monde tapait pip install -r requirements.txt
. Et ils oubliaient de lancer source .venv/bin/activate
et hop ça mettait les lib dans le répertoire
utilisateur, et ça foutait le bazar. Bref, on se prenait les pieds dans le tapis.
Alors sont nés des outils comme pipenv
et poetry
pour nous simplifier la vie. Et franchement, ils font le job. J’ai
clairement préféré poetry
à pipenv
, pour la simple et bonne raison qu’il utilise un fichier pyproject.toml
qui est
respectueux des standards Python.
Voir PEP 518 pour plus de détails.
Tout devient plus clair, on passe par la commande “poetry
” pour tout. Démarrer le projet, ajouter des dépendances,
grouper les packages de développement, etc. C’est vraiment top.
Mais… mais… je suis développeur Go, et un truc me chagrinait avec Python…
La centralisation
Quand on fait du Go, on utilise la commande “go get” pour récupérer des dépendances. Et tout est centralisé dans un seul
et même répertoire, le fameux mod cache
. Ça veut dire que si vous avez 10 projets Go, et que vous utilisez la même
librairie et la même version, elle n’est téléchargée qu’une seule fois. Et, comme Go utilise un compilateur, il fait le
lien entre la version qui se trouve dans le cache.
En clair, vous n’avez pas réellement d’environnement virtuel. Vous avez un cache de dépendances, et Go s’occupe de tout.
Beaucoup d’autres langages savent faire cela, par exemple Java avec Maven, Nodejs avec “
pnpm
”, etc.
Il y a des gens bien sur LinkedIn, et quand j’ai posé la question, un certain Thomas PEDOT me dit simplement “bah utilise UV !”
J’avais déjà regardé ce projet, construit par les mêmes auteurs que “ruff” (un excellent linter pour Python), mais je n’avais pas compris à quel point c’était génial.
uv est un gestionnaire de paquets et d’environnements virtuels pour Python qui a l’idée géniale d’utiliser des “hard links” pour faire des liens entre les paquets dans le cache et l’environnement. Mais ce n’est pas tout ! Uv gère la résolution de dépendance de manière très (non mais vriament très) efficace. Il réduit le temps d’installation à son maximum.
Leur exemple pour installer le package “Trio” sur le page de présetnation est très parlant :
Je vous disais, l’installation est centralisée, donc les packages s’installent dans un cache global. Et lorsque vous “installez” le package dans un environnement virtuel, il crée un lien “hard link” vers le cache.
En gros, voilà ce que ça donne :
Dans le graph ci-dessus, comprenez bien que les flèches représentent des liens “hard links” entre les paquets dans le cache et les environnements virtuels. Et non pas des copies !
Donc, uv, c’est cool. Il a un alias uv pip
, et j’ai deux énormes avantages :
- C’est vraiment rapide;
- je réduis considérablement l’occupation disque.
En passant mes projets Python sous uv
, sachant que j’ai régulièrement besoin de PyTorch
(torch), qui pèse 700Mo…
sur 40 projets… faites le calcul. Avec toutes les autres dépendances qui étaient dupliquées, et maintenant centralisées,
mon disque qui était à 90% d’occupation est redescendu à 60%.
C’est juste énorme.
MAIS !
Ouais il fallait bien un “mais”…
uv
est bien plus soupe au lait que poetry
. La gestion dans le ficher
pyproject.toml
est un peu lourdingue, il faut forcer le chemin des sources du projet, ça demande de taper de la conf.
Je suis pas fénéant, mais j’aime bien éviter de passer trop de temps à optimiser un simple fichier de conf.
Et là, arrive PDM.
PDM, l’autre Poetry
PDM est un gestionnaire de projet à la “poetry
”, mais avec une approche plus
fidèle aux derniers standards. Et, vous savez quoi, il sait aussi faire des installations “linkées”, donc faire ce que
fait uv
: un cache centralisé des installations.
Du moins en mettant ceci dans ~/.config/pdm/config.toml
:
[install]
cache = true
Tout comme
uv
, il fait des liens entre le cache central et les environnements virtuels.
Mais, à l’inverse de uv
, il est beaucoup plus simple à utiliser. Je retrouve le confort de poetry
, avec des options plus
claires à utiliser dans pyproject.toml
.
Pour créer un projet, c’est aussi simple que :
pdm init
Il sait même partir des options de poetry
si vous avez déjà un fichier pyproject.toml
existant. Mais j’ai préféré
refaire le fichier de conf, pour être sûr que tout soit propre.
Bon, seul bémol, bien qu’il sache faire des installations “linkées”, il utilise pip
, et donc c’est lent.
Et d’un coup, dans la doc, le Graal.
Je lis la doc (oui, je lis les docs, c’est fou hein), et je tombe sur ça : https://pdm-project.org/en/latest/usage/uv/
Attends !!! on peut utiliser uv
avec pdm
?
Le duo de choc, PDM + Uv
Une simple ligne de commande à taper, et je me dis que je suis passé à côté de ça pendant tellement de temps.
pdm config use_uv true
Cela ajoute une simple entrée dans le fichier de conf dans ~/.config/pdm/config.toml
:
use_uv = true
Et là, la vache… quand vous faites un pdm add torch
, paf, ça utilise uv
. Les dépendances “Nvidia” de la mort, avec
leur Gigaoctets de données, se pointent.
Un second projet ? Bim, quelques millisecondes pour installer la même dépendance.
Et c’est vraiment efficace dans le CI/CD
Le CD, pour “Continuous Delivery”, c’est le fait de déployer des trucs automatiquement depuis un outil qui gère ça en fonction de règles. Par exemple, Gitlab CI/CD, Github Actions, Jenkins, etc.
Mon délire avec uv
est allé loin, je fais pas mal de projets IA/ML et j’ai un JupyterHub (un Jupyter Lab
multi-utilisateurs) qui tourne sur ma bécane de dev. Et j’avais un vrai dileme à propos des “kernels python” pour gérer
des versions de paquets différentes, par notebook, etc. Mon idée a été de forcer un environnement virtuel notebook et de
forcer aussi uv pip
en lieu et place de pip
.
Et ça marche !
Donc, une soirée à mettre ça au propre, et je crée un dépôt Gitlab.

Jupyter kernel uv venv
Jupyter Lab / Hub kernel using uv to manage one virtual environment per notebook, and stop duplicating package installation.
Mais ça, c’est que dalle. Ce que j’ai vraiment kiffé, c’est la gestion de la publication de paquets sur PyPI. Dans mon
.gitlab-ci.yml
, j’ai ça :
stages:
- release
publish-package:
image: python:3.12-bookworm
stage: release
id_tokens:
PYPI_ID_TOKEN:
aud: "pypi"
before_script:
- pip install pdm
script:
- pdm publish
rules:
- if: $CI_COMMIT_TAG =~ /^v.*/
Juste ça, rien que ça…
C’est quoi cette magie là ?
Gitlab et PyPI supportent l’authentification OIDC (OpenID Connect), il faut aller configurer son compte ici et définir une entrée pour GitLab, avec le nom du projet, le chemin du fichier CI, etc. Ça prend 10 secondes.
Le id_tokens
dans le .gitlab-ci.yml
permet de récupérer un token d’authentification temporaire pour pousser le
paquet. Entendez bien, je n’ai absolment pas besoin de stocker un token dans les “variables” ou “secrets” du projet Gitlab. C’est automatique. Et c’est expliqué dans la documentation de PDM - quand je vous dis que lire les docs, c’est important…
Bref, je vous le dis
Tentez l’expérience, lisez les doc de uv
et pdm
, faites des tests.
Je sais, j’ai utilisé un ton très enthousiaste, mais je vous assure que ces deux outils m’ont vraiment soulagé. Je ne
dis pas que poetry est mauvais, je ne rejette pas pip et le fait que beaucoup de projets utilisent encore
requirements.txt
. Ce que je dis, c’est que si vous passez votre temps à gérer des dépendances, des environnements
virtuels, et que vous codez beaucoup en Python, ce couple d’outils va vous faire gagner un temps précieux, et de la
place sur votre disque.
J’ai réellement gagné 20% de mon disque, j’ai été le premier surpris. Bien sûr, passer mes projets sous pdm
m’a demandé
un peu de temps (supprimer les vieux venv
, refaire les fichiers de conf, etc.), mais franchement, ça vaut le coup.
Linux commençait vraiment à ne pas être content et malgré des phases de nettoyage podman, bleachbit, etc. j’étais à 80-90%
d’occupation disque.