uv — Gestionnaire de paquets et de projets Python rapide
Aperçu
uv est un binaire unique d'Astral qui couvre l'ensemble du workflow Python : projets avec un fichier de verrouillage multiplateforme (uv.lock), scripts mono-fichier avec dépendances en ligne, outils en ligne de commande (uvx), installation d'interpréteurs Python, et une interface uv pip de substitution. Il télécharge Python lui-même si nécessaire, de sorte qu'une machine n'a besoin que d'uv.
Instructions
Installation
# Gestionnaires de paquets
pipx install uv
brew install uv
winget install --id=astral-sh.uv -e
Astral publie également un installateur autonome pour les machines sans gestionnaire de paquets ; la page d'installation sur https://docs.astral.sh/uv/getting-started/installation/ contient la commande actuelle et les sommes de contrôle.
uv --version
uv self update # installateur autonome uniquement ; sinon, mettez à niveau avec le gestionnaire de paquets
Pour épingler une version, placez la version dans l'URL de l'installateur : https://astral.sh/uv/0.12.21/install.sh.
Créer un projet
uv init dispatch-api # application empaquetée : src/dispatch_api/, backend uv_build, script console
uv init --no-package cron-jobs # disposition à plat avec main.py et aucun système de construction
uv init --lib geo-utils # bibliothèque avec un marqueur py.typed
uv init --bare --python 3.12 # seulement pyproject.toml, dans le répertoire courant
uv init écrit également .python-version, README.md, .gitignore et initialise git. --bare n'écrit que pyproject.toml, ce qui en fait le bon choix à l'intérieur d'un dépôt existant.
Gérer les dépendances
uv add 'httpx>=0.27' 'pydantic>=2.7,<3' # dépendances d'exécution
uv add --dev pytest ruff # groupe dev, non envoyé en production
uv add --group docs mkdocs # tout groupe de dépendances nommé
uv add --optional postgres 'psycopg[binary]' # extra : pip install dispatch-api[postgres]
uv add -r requirements.txt # importer un fichier requirements existant
uv remove httpx
uv lock --upgrade-package pydantic # mettre à niveau un paquet dans ses contraintes
uv lock --upgrade # tout mettre à niveau
uv tree --outdated --depth 1 # ce qui a une version plus récente
Le premier uv add crée .venv/ et uv.lock. Chaque modification met à jour pyproject.toml, le fichier de verrouillage et l'environnement ensemble.
Exécuter et synchroniser
uv run pytest # verrouille et synchronise si nécessaire, puis s'exécute dans .venv
uv run python -m dispatch_api
uv run --with rich python -c "import rich" # un paquet supplémentaire pour cette commande uniquement
uv sync # installe tout, groupe dev inclus
uv sync --locked # CI : échoue si uv.lock ne correspond pas à pyproject.toml
uv sync --frozen --no-dev # production : utiliser uv.lock tel quel, sauter le groupe dev
uv sync --extra postgres
uv lock --check # sortie non nulle lorsque le fichier de verrouillage est périmé
Aucune activation n'est nécessaire ; uv run trouve l'environnement du projet par lui-même.
Scripts avec dépendances en ligne
uv init --script fetch-rates.py --python 3.12
uv add --script fetch-rates.py 'httpx<1' rich
uv run fetch-rates.py
uv lock --script fetch-rates.py # écrit fetch-rates.py.lock pour des exécutions reproductibles
uv add --script maintient un bloc de métadonnées en haut du fichier :
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "httpx<1",
# "rich>=15.0.0",
# ]
# ///
Ajoutez #!/usr/bin/env -S uv run --script comme première ligne et chmod +x le fichier pour l'exécuter directement.
Outils
uvx ruff check . # exécuter sans installer ; uvx = uv tool run
uvx [email protected] check . # version exacte
uvx --from 'markitdown[pdf]' markitdown q3-board-report.pdf # le nom de la commande diffère de la spécification
uv tool install ruff # installation permanente et isolée dans PATH
uv tool upgrade --all
uv tool list
uv tool uninstall ruff
Les outils installés atterrissent dans le répertoire affiché par uv tool dir --bin ; uv prévient lorsque ce répertoire n'est pas dans PATH.
Versions de Python
uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12 # écrit .python-version
uv run --python 3.13 pytest # exécution unique sur un autre interpréteur
uv python upgrade 3.12 # dernière version corrective de 3.12
uv venv --python 3.12 # environnement virtuel simple dans .venv
Les requêtes acceptent 3.12, 3.12.3, >=3.11,<3.13, [email protected] et 3.13t (sans verrou global). uv télécharge automatiquement un interpréteur manquant ; passez --no-python-downloads pour l'interdire.
Interface compatible pip
uv venv
uv pip install -r requirements.txt
uv pip compile requirements.in -o requirements.txt --universal
uv pip sync requirements.txt # supprime tout ce qui n'est pas listé
uv pip install --python .venv/bin/python 'rich>=13'
CI et Docker
name: ci
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "0.12.21"
enable-cache: true
- run: uv python install
- run: uv sync --locked --all-extras --dev
- run: uv run pytest
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:0.12.21 /uv /uvx /bin/
WORKDIR /app
ENV UV_NO_DEV=1 UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
# Les dépendances d'abord, de sorte que cette couche soit réutilisée jusqu'à ce que uv.lock change
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "-m", "dispatch_api"]
Ajoutez .venv à .dockerignore ; un environnement hôte ne fonctionne pas à l'intérieur de l'image.
Exemples
Exemple 1 : Déplacer un service requirements.txt vers un projet uv verrouillé
Demande : "Notre dépôt dispatch-api a requirements.txt et requirements-dev.txt. Déplacez-le vers uv avec un fichier de verrouillage et faites en sorte que les tests s'exécutent."
cd dispatch-api
uv init --bare --python 3.12
uv python pin 3.12
uv add -r requirements.txt
sed '/^-r /d' requirements-dev.txt | uv add --dev -r -
uv run python -m pytest -q
uv run ruff check .
Résultat : pyproject.toml liste les cinq paquets d'exécution et un groupe dev, uv.lock épingle 30 paquets, et les vérifications réussissent. Sortie abrégée :
Initialized project `dispatch-api`
Pinned `.python-version` to `3.12`
+ uvicorn==0.34.0
+ pytest==8.3.4
+ ruff==0.8.6
1 passed, 1 warning in 0.12s
All checks passed!
Exemple 2 : Un script autonome
Demande : "Écrivez un script de rapport d'utilisation du disque que je puisse copier sur n'importe quel serveur et exécuter sans configurer d'environnement."
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["rich>=13"]
# ///
import shutil
from rich.console import Console
from rich.table import Table
usage = shutil.disk_usage("/")
table = Table(title="Utilisation du disque")
table.add_column("Go total")
table.add_column("Go libre")
table.add_row(f"{usage.total / 1e9:.0f}", f"{usage.free / 1e9:.0f}")
Console().print(table)
chmod +x disk-report.py
./disk-report.py
Résultat : uv construit un environnement en cache avec rich lors de la première exécution et imprime le tableau ; les exécutions ultérieures démarrent immédiatement.
Utilisation du disque
┏━━━━━━━━━━┳━━━━━━━━━┓
┃ Go total ┃ Go libre ┃
┡━━━━━━━━━━╇━━━━━━━━━┩
│ 3936 │ 2211 │
└──────────┴─────────┘
Directives
- Validez
uv.locket.python-version. Ne modifiez jamaisuv.lockà la main ; changezpyproject.tomlou utilisezuv add,uv removeetuv lock. --lockedou--frozen:--lockedvérifie le fichier de verrouillage et échoue lorsqu'il est périmé, ce qui convient à la CI.--frozenignore la vérification et installe exactement ce que le fichier indique.uv syncest exact,uv runne l'est pas.uv syncsupprime les paquets qui ne sont pas dans le fichier de verrouillage, y compris tout ce qui a été ajouté avecuv pip install.uv runajoute seulement ce qui manque.uv pipchoisit sa cible par découverte : leVIRTUAL_ENVactif, puis.venvdans le répertoire courant ou le parent le plus proche. Exécutez depuis le mauvais dossier et il installera dans l'environnement de quelqu'un d'autre. Dans les scripts, passez--pythonavec le chemin de l'environnement.- Projets plats et pytest : avec
--bareou--no-package, le projet lui-même n'est pas installé, doncuv run pytestpeut échouer avecModuleNotFoundError. Utilisezuv run python -m pytest, ou définissezpythonpath = ["."]sous[tool.pytest.ini_options]. uv initpar défaut crée une dispositionsrc/empaquetée. Passez--no-packagepour un projet de type script avecmain.py.- Commandes expérimentales :
uv format,uv checketuv auditaffichent un avertissement indiquant qu'elles peuvent changer. Ne construisez pas encore de pipelines sur elles. - Index privés : déclarez-les sous
[[tool.uv.index]]et passez les identifiants via des variables d'environnement nommées d'après l'index : pour un index appeléinternal,UV_INDEX_INTERNAL_USERNAMEetUV_INDEX_INTERNAL_PASSWORD. Ne les validez jamais. La stratégie par défautfirst-indexprotège contre la confusion des dépendances ; évitezunsafe-best-match. - Chaîne d'approvisionnement :
uv run,uvxet les scripts avec métadonnées en ligne téléchargent et exécutent des paquets. Examinez la liste des dépendances de tout script provenant d'une source non fiable avant de l'exécuter. uv self updatefonctionne uniquement pour les installations effectuées avec l'installateur autonome.- Cache CI : exécutez
uv cache prune --ciavant de sauvegarder le cache pour le maintenir petit. - Quand NE PAS l'utiliser : uv installe à partir d'index de paquets Python, de git et de chemins locaux. Il n'installe pas de paquets conda ou de bibliothèques système, donc gardez conda pour les piles qui en dépendent.