- En passant à uv, la vitesse d’installation des dépendances Python devient environ 10 fois plus rapide qu’avec pip, et l’exécution reste possible avec un utilisateur non root sans venv séparé
- Avec pyproject.toml comme base, il suffit de déclarer les dépendances de premier niveau et uv gère automatiquement le fichier de lock, avec une gestion de l’arbre des dépendances et des versions exactes supérieure à
pip freeze
- Dans le Dockerfile, des changements étape par étape sont nécessaires, notamment la copie des binaires uv et uvx, l’utilisation des fichiers pyproject.toml/uv.lock et la configuration de variables d’environnement
- Des commandes comme uv sync/add/remove et
uv:outdated permettent de gérer facilement l’ajout, la suppression, la mise à jour des dépendances ainsi que la vérification des dernières versions des paquets
- Une gestion régulière du fichier de lock et des mises à jour de dépendances devient possible, ce qui améliore la cohérence en environnement de collaboration et de déploiement
Installation des dépendances 10 fois plus rapide, sans venv, avec un environnement non root
- uv est un outil qui améliore fortement la vitesse d’installation des dépendances dans les projets Python par rapport à pip
- Avec l’adoption d’uv, il est possible de constater une vitesse d’installation environ 10 fois plus rapide que pip dans divers projets comme Flask ou Django
- Même sans environnement virtuel séparé (
venv), l’exécution dans le conteneur reste sûre avec un utilisateur non root
pyproject.toml vs requirements.txt
- Au lieu du traditionnel
requirements.txt, il suffit d’indiquer uniquement les dépendances de premier niveau dans le fichier pyproject.toml, puis uv génère automatiquement le fichier uv.lock
- Ajouter la section
[project] dependencies dans pyproject.toml
- Supprimer l’ancien
requirements.txt
- Le fichier de lock d’uv ressemble au résultat de
pip freeze, mais inclut un arbre de dépendances précis et des informations de version exactes
Modifications de la configuration du Dockerfile
- Utiliser les binaires uv et uvx copiés dans le conteneur (binaires Rust compilés statiquement)
- Copier les fichiers
pyproject.toml, uv.lock\* à la place des anciens requirements*.txt
- Ajouter des variables d’environnement :
UV_COMPILE_BYTECODE=1 : précompiler en bytecode pendant l’étape de build
UV_PROJECT_ENVIRONMENT="/home/python/.local" : installer les paquets dans un chemin spécifique sans créer de venv séparé
- Remplacer aussi la commande d’installation des dépendances, de
pip3-install vers uv-install
- Exemple :
RUN chmod 0755 bin/* && bin/uv-install
Gestion des dépendances : ajout, suppression, mise à jour, etc.
- Il est possible d’exécuter les commandes uv dans le conteneur via un script
run dédié
./run deps:install : installe après build de l’image tout en exportant le fichier de lock vers l’hôte
./run deps:install --no-build : met à jour uniquement le fichier de lock sans rebuild
./run uv add mypackage --no-sync : met à jour uniquement pyproject.toml et le fichier de lock, l’installation réelle étant lancée séparément
./run uv remove mypackage --no-sync : supprime un paquet
./run uv:outdated : vérifie les dernières versions disponibles des dépendances actuelles
Vidéo et guide pratique fournis
- Une démo réelle et des exemples de
git diff sont fournis pour l’adoption d’uv, la rédaction de pyproject.toml, les modifications du Dockerfile, les commandes lock/sync, l’ajout/la suppression de dépendances et la vérification des versions les plus récentes
- Il est aussi possible de consulter les diff de migration pour deux projets Flask et Django
2 commentaires
J’envisageais justement de migrer ce que je déployais avec Poetry, et ça a l’air stable et simple ^^
Commentaire Hacker News
Il faut noter que uv prend en charge un workflow qui remplace directement pyenv, virtualenv et pip. Ce n’est pas un outil qui impose forcément un lockfile ou
pyproject.toml. Avec la commandeuv python pin <version>, il crée un fichier.python-versiondans le répertoire courant ; avecuv virtualenv, il télécharge la version de Python correspondante comme pyenv puis crée un environnement virtuel.venv; avecuv pip install -r requirements.txt, il installe les paquets derequirements.txt; avecuv run <command>, il peut exécuter une commande en incluant les variables d’environnement du fichier.env. Attention toutefois aux problèmes de priorité des variables d’environnement (issue liée)uv pipsoit lent et je ne sais pas pourquoi ; c’est peut-être lié au réseau de l’entreprisepyproject.toml, donc je me demande si le fichier.python-versionest vraiment nécessaireCette approche vide en grande partie le lock file de sa raison d’être. Si le fichier est absent ou invalide, cela signifie qu’il y a un vrai problème avec le lock file, et il vaut mieux qu’une personne familière du projet concerné intervienne directement. Sinon, il n’y a pas vraiment de raison d’avoir un lock file. En CI, remplacer automatiquement le lock file peut créer de la confusion
uv lockéchoue avec un message explicite, et leerrexitdu script shell interrompt immédiatement l’exécution. La redirection d’erreur deuv lock --checksert à éviter que la même erreur soit affichée deux fois. Si on casse volontairement le lock file puis qu’on exécute le script, le build s’arrête avec un message d’erreur précis. Le script a été réécrit avecif-elsepour être plus clair. Si le lock file n’existe pas, le bon flux est bien d’en générer un nouveau. Il suffit ensuite de le commituv sync --locked. Si le lock file est absent ou obsolète, l’échec est explicite. Je recommande de toujours faire les builds avec l’option--locked--frozen, on s’attend justement à ce que le lock file ne soit pas mis à jour, mais en pratique c’est l’inverse qui se produit. Je suis d’accord sur le fait que si le lock file est absent ou ne correspond pas, il faut une intervention humaineJe suis complètement opposé au fait que des outils Python soient développés dans autre chose que Python. On a déjà le C, CPython est standardisé, donc il n’y a pas besoin d’un nouveau langage comme Rust. Le package Pendulum a mis plus de 7 mois à supporter 3.13, et je pense que c’est parce qu’il y avait trop peu de personnes capables de corriger le problème à cause du code natif Rust. Si ça avait été du C, je l’aurais corrigé moi-même. (issue liée) Dans l’idéal, si on veut un datetime rapide en Rust ou dans un autre langage externe, il vaudrait mieux le faire sous une forme exploitable via FFI par plusieurs langages. Les bases en Rust ne m’enthousiasment toujours pas, et je comprends mieux pourquoi la communauté Linux est réticente
Il faut être prudent quand on utilise uv à la place de pip. Par défaut, il ne génère pas de fichiers pyc, ce qui peut ralentir le démarrage du service (référence)
Quand on essaie uv dans un conteneur Flask, la différence de temps de build devient presque ennuyeusement énorme, et le processus d’installation devient en plus très prévisible. On n’a plus la mauvaise surprise de versions de dépendances qui changent avec pip. On utilise
pyproject.toml, on lanceuv lock, et c’est terminé. Avec Docker, il suffit de copier uniquementpyproject.tomletuv.lock(HOT COPY), puis d’exécuteruv sync --frozen --no-install-project: cela permet de mettre en cache la couche d’installation sans inclure le code de l’application. Quiconque a déjà souffert d’une reconstruction complète de la couche pour un simple changement de paquet comprend pourquoi c’est important. Avec la variable d’environnementUV_PROJECT_ENVIRONMENT=/home/python/.local, on peut préchauffer l’image de base sans venv, ce qui permet de partager les builds et de réduire les coûts d’infrastructure. L’optionUV_COMPILE_BYTECODE=1génère les fichiers.pycau moment du build. On supprime ainsi les environnements mutables et on impose la reproductibilité ; désormais, si le build échoue, la responsabilité du lockfile est claireMême en 2025, le packaging Python et la gestion des dépendances restent toujours aussi confus
requirements.txtetvenvme suffisent largementJe suis curieux d’avoir une comparaison de sécurité entre les gestionnaires de paquets Python comme uv, pip, conda, etc. La vitesse est appréciable, mais la sécurité d’un gestionnaire de paquets me paraît bien plus importante
Comme je publie des paquets sur PyPI, j’aimerais personnellement utiliser uv pour sa rapidité, mais s’il n’y a pas de garantie qu’il se comporte exactement comme pip, je ne peux pas facilement basculer. Si un utilisateur rencontre une erreur avec «
pip install xxx», je dois pouvoir la reproduire et la déboguer dans le même environnementJ’ai l’impression que UV fait partie des évolutions les plus positives du packaging Python récent : on l’exécute et il donne de bons résultats
Il mentionne aussi un excellent guide sur l’utilisation de uv pour construire des conteneurs de production (voir le guide)