Saltar al contenido principal
~/avilesxd/uv-0-12-el-gestor-de-python-que-ya-supero-a-pip

uv 0.12: el gestor de Python que ya dejó atrás a pip y venv

·6 min read·Ignacio Avilés
compartir:TwitterLinkedIn

uv 0.12: el gestor de Python que ya dejó atrás a pip y venv

Si todavía usás pip install -r requirements.txt y armás un virtualenv a mano con python -m venv .venv, este post es para vos. La herramienta uv, del equipo de Astral (los mismos detrás de Ruff), acaba de llegar a la versión 0.12 con cambios que la convierten en la opción por default para cualquier proyecto nuevo en Python. Y no es hype: es velocidad, reproducibilidad y menos boilerplate.

Por qué uv existe

Durante años el flujo de trabajo de un dev Python fue una secuencia conocida: instalar Python, crear un virtualenv, activar el venv, escribir un requirements.txt con versiones pinneadas, y rezar para que en la máquina del compañero se instale todo igual. En 2024 Astral presentó uv como un reemplazo moderno escrito en Rust que colapsa todos esos pasos en uno solo.

Lo que empezó como un "pip pero rápido" hoy es un gestor completo de proyectos: maneja versiones de Python, dependencias, lockfiles, scripts, builds y publicación en PyPI. La versión 0.12 consolida esa visión con un cambio fuerte en cómo se inicializa un proyecto.

Qué trae uv 0.12

El cambio central: uv init ahora genera un proyecto con layout src/, configura uv_build como backend por default y crea un entry point ejecutable. Es decir, dejás de tener un main.py suelto en la raíz.

Antes de la 0.12, uv init te dejaba esto:

mi-proyecto/
├── main.py
├── pyproject.toml
└── README.md

Ahora te deja esto:

mi-proyecto/
├── pyproject.toml
├── README.md
└── src/
    └── mi_proyecto/
        ├── __init__.py
        └── __init__.py   # contiene una función main() tipada

El cambio no es cosmético. El layout src/ es el que recomienda la guía oficial de packaging de Python porque evita el clásico problema de importar la versión "del código fuente" cuando en realidad querés importar la versión instalada. Si alguna vez te pasó que tu test pasaba en local pero el CI rompía, probablemente estabas en flat layout y este layout lo soluciona.

Además, el pyproject.toml ahora define un bloque project.scripts con un alias listo para correr:

[project.scripts]
mi-proyecto = "mi_proyecto:main"

Eso significa que después de uv sync podés ejecutar uv run mi-proyecto y se llama a la función main() del paquete. Nada de if __name__ == "__main__": ni de armar CLIs a mano para un script chico.

Instalación en 30 segundos

Si tenés macOS o Linux, una línea y listo:

curl -LsSf https://astral.sh/uv/install.sh | sh

En Windows, el instalador está en docs.astral.sh/uv. Después de instalar, verificá:

uv --version
# uv 0.12.0

Del requirements.txt a un proyecto real

Vamos a lo concreto. Supongamos que querés armar un script para descargar videos de YouTube, similar al que ya vimos en el post [Descargar Videos de YouTube con Python](Descargar Videos de YouTube con Python.md). El flujo con uv es así:

1. Inicializar el proyecto

uv init yt-downloader
cd yt-downloader

Eso te crea la estructura nueva con src/. Si querés el layout viejo, podés pasar --package=false, pero la recomendación del propio Astral es el nuevo.

2. Sumar dependencias

uv add pytube tkinter

Este comando edita el pyproject.toml, crea un uv.lock y deja todo listo. El lockfile es la pieza clave: garantiza que vos, tu compañero y tu CI instalen exactamente las mismas versiones. Reemplaza al requirements.txt y al pip freeze en un solo archivo.

3. Correr el script

uv run yt-downloader

uv run se encarga de crear el virtualenv, instalar las dependencias declaradas y ejecutar el entry point. No hace falta activar nada.

4. Manejar la versión de Python

¿Necesitás asegurarte de que todos usen Python 3.12? Lo declarás en pyproject.toml:

[project]
requires-python = ">=3.12"

Y uv se encarga de descargar la versión correcta automáticamente con uv python install 3.12. Si tu sistema tiene otra versión, no importa: uv la baja on demand y la usa para tu proyecto sin tocar tu instalación global.

Cómo se compara con el flujo clásico

Una comparación directa para que se vea el ahorro real:

TareaFlujo clásicoCon uv
Crear venvpython -m venv .venv && source .venv/bin/activateImplícito en uv run
Instalar dependenciaspip install -r requirements.txtuv sync
Congelar versionespip freeze > requirements.txtuv.lock automático
Cambiar versión PythonInstalar a mano o usar pyenvuv python install 3.12
Publicar en PyPIpython -m build && twine upload ...uv publish

La diferencia de velocidad es notable: uv resuelve e instala dependencias entre 10 y 100 veces más rápido que pip porque hace la resolución en paralelo y cachea los wheels en ~/.cache/uv/. En un proyecto mediano con cientos de dependencias, lo que antes tardaba un minuto, ahora termina en pocos segundos.

Migrar un proyecto existente no es traumático

Si ya tenés un proyecto con requirements.txt, el camino es:

  1. Inicializá uv en la raíz: uv init --bare .
  2. Importá las dependencias actuales: uv add -r requirements.txt
  3. Borrá el requirements.txt y empezá a commitear el uv.lock.
  4. Reemplazá los pasos de tu README para usar uv sync y uv run.

El uv sync lee el lockfile y deja el entorno idéntico en cualquier máquina. En CI, podés cachear ~/.cache/uv/ y bajar el tiempo de instalación a casi cero a partir de la segunda corrida.

Tip: Si tu proyecto es una librería que se publica en PyPI, el nuevo uv_build backend es lo que necesitás. Reemplaza a setuptools y hatchling como opción por default, y como está escrito en Rust es sensiblemente más rápido para builds grandes.

Algo que veo venir

El propio Simon Willison se preguntó en su blog cuándo Astral va a marcar a uv como 1.0. La respuesta obvia es que todavía hay esquinas por pulir (particularmente la compatibilidad con proyectos que usan setup.py legacy), pero la velocidad a la que el proyecto incorporó features nuevas en los últimos 12 meses hace pensar que el 1.0 está cerca. Mientras tanto, ya hay empresas corriendo uv en producción, así que no es una tecnología riesgosa para adoptar.

Lo que sí me parece claro es que el flujo "venv + pip + requirements.txt" se va a sentir tan arcaico en dos años como se siente hoy el python setup.py install. Si tenés la chance de elegir para un proyecto nuevo, no hay razón seria para no empezar con uv.

Y si querés ver otros flows de tooling moderno, te dejo el post de Docker para desarrolladores y el de GitHub Actions para sincronizar Obsidian con tu blog. Mismo espíritu: reemplazá el flujo manual de toda la vida por una herramienta que lo automatiza.

comentarios

$ subscribe --newsletter

Recibe los nuevos posts en tu email

Un email cuando publico algo nuevo. Sin ruido, sin relleno.

Sin spam. Baja en cualquier momento. Política de privacidad.