¿Qué hace uv — Gestor rápido de paquetes y proyectos Python?
Resumen
uv es un único binario de Astral que cubre todo el flujo de trabajo de Python: proyectos con un archivo de bloqueo multiplataforma (uv.lock), scripts de un solo archivo con dependencias inline, herramientas de línea de comandos (uvx), instalación de intérpretes de Python y una interfaz uv pip compatible. Descarga Python por sí mismo cuando es necesario, por lo que una máquina solo necesita uv.
Instrucciones
Instalación
# Gestores de paquetes
pipx install uv
brew install uv
winget install --id=astral-sh.uv -e
Astral también publica un instalador independiente para máquinas sin gestor de paquetes; la página de instalación en https://docs.astral.sh/uv/getting-started/installation/ tiene el comando actual y las sumas de verificación.
uv --version
uv self update # solo instalador independiente; de lo contrario, actualiza con el gestor de paquetes
Para fijar una versión, coloca la versión en la URL del instalador: https://astral.sh/uv/0.12.21/install.sh.
Crear un proyecto
uv init dispatch-api # aplicación empaquetada: src/dispatch_api/, backend uv_build, script de consola
uv init --no-package cron-jobs # diseño plano con main.py y sin sistema de compilación
uv init --lib geo-utils # librería con marcador py.typed
uv init --bare --python 3.12 # solo pyproject.toml, en el directorio actual
uv init también escribe .python-version, README.md, .gitignore e inicializa git. --bare escribe solo pyproject.toml, lo que lo convierte en la opción correcta dentro de un repositorio existente.
Gestionar dependencias
uv add 'httpx>=0.27' 'pydantic>=2.7,<3' # dependencias de ejecución
uv add --dev pytest ruff # grupo dev, no se envía a producción
uv add --group docs mkdocs # cualquier grupo de dependencias con nombre
uv add --optional postgres 'psycopg[binary]' # extra: pip install dispatch-api[postgres]
uv add -r requirements.txt # importar un archivo requirements existente
uv remove httpx
uv lock --upgrade-package pydantic # actualizar un paquete dentro de sus restricciones
uv lock --upgrade # actualizar todo
uv tree --outdated --depth 1 # qué tiene una versión más reciente
El primer uv add crea .venv/ y uv.lock. Cada cambio actualiza pyproject.toml, el archivo de bloqueo y el entorno simultáneamente.
Ejecutar y sincronizar
uv run pytest # bloquea y sincroniza si es necesario, luego ejecuta dentro de .venv
uv run python -m dispatch_api
uv run --with rich python -c "import rich" # un paquete adicional solo para este comando
uv sync # instala todo, incluido el grupo dev
uv sync --locked # CI: falla si uv.lock no coincide con pyproject.toml
uv sync --frozen --no-dev # producción: usa uv.lock tal cual, omite el grupo dev
uv sync --extra postgres
uv lock --check # sale con código distinto de cero cuando el archivo de bloqueo está desactualizado
No es necesaria activación; uv run encuentra el entorno del proyecto por sí mismo.
Scripts con dependencias inline
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 # escribe fetch-rates.py.lock para ejecuciones reproducibles
uv add --script mantiene un bloque de metadatos al principio del archivo:
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "httpx<1",
# "rich>=15.0.0",
# ]
# ///
Agrega #!/usr/bin/env -S uv run --script como primera línea y chmod +x al archivo para ejecutarlo directamente.
Herramientas
uvx ruff check . # ejecutar sin instalar; uvx = uv tool run
uvx [email protected] check . # versión exacta
uvx --from 'markitdown[pdf]' markitdown q3-board-report.pdf # el nombre del comando difiere del spec
uv tool install ruff # instalación permanente y aislada en PATH
uv tool upgrade --all
uv tool list
uv tool uninstall ruff
Las herramientas instaladas se ubican en el directorio que imprime uv tool dir --bin; uv advierte cuando ese directorio no está en PATH.
Versiones de Python
uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12 # escribe .python-version
uv run --python 3.13 pytest # ejecución única con otro intérprete
uv python upgrade 3.12 # último parche de 3.12
uv venv --python 3.12 # entorno virtual simple en .venv
Las solicitudes aceptan 3.12, 3.12.3, >=3.11,<3.13, [email protected] y 3.13t (sin GIL). uv descarga automáticamente un intérprete faltante; pasa --no-python-downloads para prohibirlo.
Interfaz compatible con pip
uv venv
uv pip install -r requirements.txt
uv pip compile requirements.in -o requirements.txt --universal
uv pip sync requirements.txt # elimina cualquier cosa no listada
uv pip install --python .venv/bin/python 'rich>=13'
CI y 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
# Primero las dependencias, para que esta capa se reutilice hasta que cambie uv.lock
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"]
Agrega .venv a .dockerignore; un entorno anfitrión no funciona dentro de la imagen.
Ejemplos
Ejemplo 1: Migrar un servicio con requirements.txt a un proyecto uv bloqueado
Solicitud: "Nuestro repositorio dispatch-api tiene requirements.txt y requirements-dev.txt. Muévelo a uv con un archivo de bloqueo y haz que las pruebas se ejecuten."
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 .
Resultado: pyproject.toml lista los cinco paquetes de ejecución y un grupo dev, uv.lock fija 30 paquetes y las comprobaciones pasan. Salida resumida:
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!
Ejemplo 2: Un script autónomo
Solicitud: "Escribe un script de informe de uso de disco que pueda copiar a cualquier servidor y ejecutar sin configurar un entorno."
#!/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="Uso de disco")
table.add_column("Total GB")
table.add_column("Libre GB")
table.add_row(f"{usage.total / 1e9:.0f}", f"{usage.free / 1e9:.0f}")
Console().print(table)
chmod +x disk-report.py
./disk-report.py
Resultado: uv construye un entorno en caché con rich en la primera ejecución e imprime la tabla; las ejecuciones posteriores comienzan inmediatamente.
Uso de disco
┏━━━━━━━━━━┳━━━━━━━━━┓
┃ Total GB ┃ Libre GB ┃
┡━━━━━━━━━━╇━━━━━━━━━┩
│ 3936 │ 2211 │
└──────────┴─────────┘
Directrices
- Confirma
uv.locky.python-version. Nunca editesuv.locka mano; cambiapyproject.tomlo usauv add,uv removeyuv lock. --lockedo--frozen:--lockedverifica el archivo de bloqueo y falla cuando está desactualizado, lo que es adecuado para CI.--frozenomite la verificación e instala exactamente lo que dice el archivo.uv synces exacto,uv runno lo es.uv syncelimina los paquetes que no están en el archivo de bloqueo, incluido cualquier cosa agregada conuv pip install.uv runsolo agrega lo que falta.uv pipelige su destino por descubrimiento: elVIRTUAL_ENVactivo, luego.venven el directorio actual o en el padre más cercano. Ejecuta desde la carpeta incorrecta e instalará en el entorno de otro. En los scripts pasa--pythoncon la ruta del entorno.- Proyectos planos y pytest: con
--bareo--no-packageel proyecto en sí no está instalado, por lo queuv run pytestpuede fallar conModuleNotFoundError. Usauv run python -m pytest, o establecepythonpath = ["."]bajo[tool.pytest.ini_options]. uv initpor defecto crea un diseño empaquetadosrc/. Pasa--no-packagepara un proyecto estilo script conmain.py.- Comandos experimentales:
uv format,uv checkyuv auditmuestran una advertencia de que pueden cambiar. No construyas pipelines basados en ellos todavía. - Índices privados: decláralos bajo
[[tool.uv.index]]y pasa las credenciales a través de variables de entorno nombradas según el índice: para un índice llamadointernal,UV_INDEX_INTERNAL_USERNAMEyUV_INDEX_INTERNAL_PASSWORD. Nunca los confirmes. La estrategia predeterminadafirst-indexprotege contra la confusión de dependencias; evitaunsafe-best-match. - Cadena de suministro:
uv run,uvxy los scripts con metadatos inline descargan y ejecutan paquetes. Revisa la lista de dependencias de cualquier script de una fuente no confiable antes de ejecutarlo. uv self updatefunciona solo para instalaciones realizadas con el instalador independiente.- Caché de CI: ejecuta
uv cache prune --ciantes de guardar la caché para mantenerla pequeña. - Cuándo NO usarlo: uv instala desde índices de paquetes Python, git y rutas locales. No instala paquetes conda ni bibliotecas del sistema, así que mantén conda para stacks que dependan de ellos.