Gestion moderne de projet Python avec uv

Temps de lecture15 min

En bref

Résumé de l’article

Les outils historiques de l’écosystème Python – venv pour isoler un projet, pip pour y installer des bibliothèques – fonctionnent, mais imposent une gymnastique quotidienne : penser à activer l’environnement, attendre les téléchargements, et se contenter d’un requirements.txt qui ne garantit pas vraiment que tout le monde travaille sur les mêmes versions.

Cet article présente uv, un outil unique qui remplace tout cela. Il explique les trois idées qui le font tenir : l’environnement .venv créé et maintenu automatiquement, l’exécution par uv run qui dispense d’activer quoi que ce soit, et le couple pyproject.toml / uv.lock qui sépare ce que vous déclarez de ce qui est réellement installé. Quatre commandes suffisent à couvrir l’usage quotidien.

Points clés à retenir

  • Un outil tout-en-un ultra-rapide : Écrit en Rust, uv remplace à lui seul plusieurs outils historiques (pip, venv, pip-tools, virtualenv) avec des temps d’installation quasi instantanés grâce à un cache global partagé.
  • Exécution sans activation permanente : Grâce à uv run, vous n’avez plus besoin d’activer manuellement votre environnement virtuel (source .venv/bin/activate ou activate.bat) : uv cible automatiquement le bon interpréteur.
  • Configuration standard avec pyproject.toml : Vos dépendances directes sont déclarées proprement dans le fichier standard du projet.
  • Reproductibilité garantie avec uv.lock : uv génère un fichier de verrouillage assurant que tous les collaborateurs d’un projet utilisent strictement les mêmes versions de bibliothèques.

Contenu de l’article

Pourquoi uv ? Vers une gestion moderne de Python

La fiche Installer des bibliothèques avec pip et venv décrit le flux de travail traditionnel de l’écosystème Python :

python -m venv env1
env1\Scripts\activate
python -m pip install numpy matplotlib
python -m pip freeze > requirements.txt
python -m venv env1
env1\Scripts\Activate.ps1
python -m pip install numpy matplotlib
python -m pip freeze > requirements.txt
python3 -m venv env1
source env1/bin/activate
python3 -m pip install numpy matplotlib
python3 -m pip freeze > requirements.txt
python3 -m venv env1
source env1/bin/activate
python3 -m pip install numpy matplotlib
python3 -m pip freeze > requirements.txt

Bien que fonctionnel, ce mode de fonctionnement présente trois limites majeures au quotidien :

  1. L’oubli fréquent d’activation/synchronisation de l’environnement : dès que vous ouvrez un nouveau terminal, l’environnement virtuel n’est pas activé ou incomplet. Taper python mon_script.py provoque alors une erreur ModuleNotFoundError car l’ordinateur utilise le Python du système à la place de celui du projet ou bien que les dépendances installées ne sont pas à jour.
  2. La lenteur d’installation des paquets : pip télécharge et réinstalle les bibliothèques séparément pour chaque projet. Sur des bibliothèques de calcul scientifique volumineuses (numpy, scipy, matplotlib), l’attente peut être longue.
  3. Le manque de reproductibilité stricte : pip freeze capture en vrac l’état de la machine locale (y compris des paquets indirects ou spécifiques à votre système d’exploitation), sans garantir qu’un coéquipier obtiendra exactement les mêmes versions sur son ordinateur.

uv a été conçu pour résoudre l’ensemble de ces problèmes au sein d’un exécutable unique, moderne et très rapide.

Installer uv

Pour installer uv sur votre machine, une seule commande dans un terminal suffit. En se référant à la documentation officielle, voici celle qui correspond à votre système d’exploitation :

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Important

Si Windows bloque l’exécution de uv --version, utilisez plutôt la commande suivante :

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/0.12.10/install.ps1 | iex
curl -LsSf https://astral.sh/uv/install.sh | sh
curl -LsSf https://astral.sh/uv/install.sh | sh

La documentation propose des commandes alternatives si certains outils comme curlne sont pas installés. N’hésitez pas à consulter la documentation officielle si vous rencontrez des problèmes d’installation.

Comment fonctionne uv dans les grandes lignes ?

uv repose sur trois principes simples :

L’environnement virtuel automatique (.venv)

Lorsque vous travaillez sur un projet, uv crée au besoin et maintient un dossier isolé nommé .venv à la racine de votre dossier de travail. Ce dossier contient l’interpréteur Python et les bibliothèques propres à ce projet. Vous n’avez pas à le créer vous-même : la première commande qui en a besoin – uv add, uv run ou uv sync – le fabrique au passage.

C’est l’un des plus grands atouts de uv : vous n’avez plus besoin d’activer l’environnement virtuel.

La commande :

uv run python main.py
uv run python main.py
uv run python main.py
uv run python main.py
effectue automatiquement les opérations suivantes en une fraction de seconde :

  • Elle vérifie que l’environnement .venv existe et qu’il contient bien les paquets nécessaires.
  • Elle lance l’interpréteur Python situé dans ce .venv pour exécuter votre script.

Même si vous ouvrez un nouveau terminal ou redémarrez votre machine, uv run exécutera toujours votre code dans le bon environnement.

Le cache global partagé

uv télécharge chaque bibliothèque une seule fois dans un cache centralisé sur votre disque dur. Lorsqu’un autre projet a besoin du même paquet, uv le lie instantanément sans avoir à le retélécharger ni à dupliquer l’espace disque.

La standardisation des projets

Le fichier pyproject.toml : standard de projet Python

Un projet Python moderne s’articule autour d’un fichier de configuration unique : le pyproject.toml (norme officielle PEP 518 / PEP 621).

Rédigé au format TOML (un format de configuration minimaliste et lisible), il centralise la description du projet et la liste des bibliothèques dont votre code a besoin :

[project]
name = "tp-maths"
version = "0.1.0"
description = "Calculs d'intégrales et tracés graphiques"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "matplotlib>=3.9.0",
    "numpy>=2.0.0",
    "scipy>=1.14.0",
]

Les champs essentiels :

  • name & version : identifient votre projet.
  • requires-python : définit la version minimale de Python requise.
  • dependencies : liste vos dépendances directes. Lorsque vous tapez uv add scipy, uv vient automatiquement ajouter scipy dans cette liste.
La règle d’or : pyproject.toml vs uv.lock

Pour assurer un travail en groupe sans mauvaises surprises, uv sépare clairement votre déclaration de la réalité technique :

pyproject.toml  ───>  Votre INTENTION    (les paquets que vous déclarez : numpy, scipy, ...)
   uv.lock      ───>  L'ÉTAT EXACT       (les versions précises de tous les sous-paquets)
   .venv/       ───>  L'ENVIRONNEMENT    (les fichiers installés sur votre disque)
  1. pyproject.toml exprime votre intention : c’est un fichier clair rédigé pour les humains, qui déclare les bibliothèques nécessaires à votre code.
  2. uv.lock enregistre l’état exact verrouillé : généré et maintenu par uv, ce fichier consigne les numéros de version précis et les sommes de contrôle (hashes) de chaque paquet et de ses sous-dépendances. Il garantit que tout le monde travaillera sur les mêmes versions.
  3. .venv est le résultat local : c’est le dossier qui contient les fichiers exécutables de Python et des bibliothèques sur votre machine.
Important

Vous allez très rapidement travailler à plusieurs sur un même code à l’aide d’un logiciel de gestion de versions (Git et GitLab). Il faudra alors être vigilant car :

  • pyproject.toml et uv.lock DOIVENT être synchronisés dans votre dépôt Git.
  • Le dossier .venv ne doit JAMAIS être envoyé sur Git : il est recréé à l’identique sur n’importe quel ordinateur grâce à la commande uv sync. Ces règles vous seront rappelées lors de la prochaine session.

Les 4 commandes uv indispensables au quotidien

Commande Rôle Quand l’utiliser ?
uv init --no-package Crée les fichiers de base du projet dans le dossier courant : pyproject.toml, .python-version, main.py, README.md, et un dépôt Git (.git, .gitignore). Au démarrage d’un TP ou d’un projet.
uv add numpy Installe une bibliothèque (ici numpy), l’enregistre dans pyproject.toml et verrouille sa version dans uv.lock. Crée .venv s’il n’existe pas encore. Dès que votre code a besoin d’une nouvelle bibliothèque.
uv run python main.py Exécute un script avec l’interpréteur de l’environnement virtuel du projet. Pour lancer vos programmes sans avoir à activer l’environnement.
uv sync Installe dans .venv toutes les dépendances aux versions inscrites dans uv.lock. En récupérant un projet dont vous n’avez que pyproject.toml et uv.lock – par exemple celui d’un(e) camarade, ou un dépôt Git.

Un mot sur l’option --no-package : elle indique à uv que nous créons une application avec un point d’entrée main.py, et non une bibliothèque destinée à être publiée. Sans elle, uv init prépare une arborescence src/mon_projet/ et un système de packaging, superflus pour un TP.

Notez par ailleurs que uv init crée au passage un dépôt Git dans le dossier (.git, .gitignore). Le versionnage est abordé en séance 3.

Ces quatre commandes couvrent l’essentiel de votre usage cette année. Le réflexe à retenir est que vous ne manipulez jamais l’environnement virtuel directement : vous déclarez ce dont votre code a besoin avec uv add, et vous lancez votre code avec uv run. uv s’occupe du reste, y compris de créer .venv au bon moment.

Pour aller plus loin

uv intègre également des fonctionnalités avancées très pratiques :

  • Exécuter des outils sans les installer dans le projet (uvx) :
    La commande uvx permet d’exécuter à la volée un utilitaire disponible sur PyPI dans un environnement éphémère. Par exemple, pour formater ou vérifier la qualité de son code avec le linter Ruff :

    uvx ruff check .
    uvx ruff format .
    uvx ruff check .
    uvx ruff format .
    uvx ruff check .
    uvx ruff format .
    uvx ruff check .
    uvx ruff format .

  • Gérer plusieurs versions de Python (uv python) :
    uv peut installer lui-même différentes versions de Python de manière isolée, sans toucher aux installations du système :

    uv python list          # Affiche les versions disponibles et installées
    uv python install 3.12  # Installe Python 3.12
    uv python list          # Affiche les versions disponibles et installées
    uv python install 3.12  # Installe Python 3.12
    uv python list          # Affiche les versions disponibles et installées
    uv python install 3.12  # Installe Python 3.12
    uv python list          # Affiche les versions disponibles et installées
    uv python install 3.12  # Installe Python 3.12

  • Scripts mono-fichier autonomes (PEP 723) :
    Pour un script isolé d’un seul fichier, vous pouvez déclarer ses dépendances directement dans un bloc d’en-tête :

    # /// script
    # dependencies = ["matplotlib"]
    # ///
    import matplotlib.pyplot as plt
    plt.plot([1, 2, 3], [1, 4, 9])
    plt.show()

    Exécutez-le simplement avec uv run script.py : uv créera un environnement temporaire pour installer matplotlib et lancer le tracé.