uv reúne creación de entornos, gestión de versiones de Python, resolución de dependencias, lockfiles y ejecución de comandos. No cambia cómo escribes Python; hace más explícita la reproducción del proyecto.

Si estos archivos son nuevos para ti, revisa pyproject.toml y los entornos virtuales.

Crear y ejecutar un proyecto

Instala uv con la guía oficial y ejecuta:

uv init analizador
cd analizador
uv add requests
uv run python main.py

uv add registra la dependencia en pyproject.toml, resuelve versiones y actualiza uv.lock. .venv se crea cuando hace falta. No versiones el entorno; versiona la configuración y, en una aplicación, el lockfile.

Al clonar el repositorio:

uv sync
uv add --dev pytest ruff
uv run pytest

Este flujo también encaja con GitHub Actions.

Migrar desde requirements.txt

uv init
uv add -r requirements.txt
uv lock
uv sync

Haz la migración en una rama y ejecuta todas las pruebas. Dependencias sin límites pueden resolverse de otra forma. La documentación oficial de proyectos explica entornos, lock y ejecución.

  • Declara versiones compatibles con requires-python.
  • Usa uv add y uv remove en lugar de modificar el entorno a mano.
  • Revisa los cambios de uv.lock.
  • No mezcles gestores sin una razón documentada.

La ventaja principal no es solo la velocidad: uv crea un camino único entre metadatos, entorno local y CI. Pruébalo primero en un proyecto pequeño.

Comprender qué representa cada archivo

Configuración, resolución e instalación son conceptos relacionados, pero no equivalentes. pyproject.toml declara la intención del proyecto: nombre, rango de Python y dependencias directas. uv.lock registra una resolución completa, incluidas las dependencias transitivas y los artefactos compatibles con cada plataforma. .venv es la instalación local y descartable que se construye a partir de esos archivos.

Por eso eliminar .venv no destruye el proyecto. Si los archivos versionados son correctos, uv sync puede reconstruir el entorno. También explica por qué instalar un paquete mediante una interfaz compatible con pip no equivale a uv add: la instalación puede modificar el entorno sin registrar la decisión en el proyecto.

En una aplicación conviene versionar uv.lock para que pruebas y despliegues consuman una solución revisada. Una biblioteca también puede usarlo durante el desarrollo, pero sus usuarios resolverán las dependencias según los rangos publicados. Por ese motivo, una biblioteca debe probar límites de compatibilidad relevantes, no solamente la combinación bloqueada.

Separar dependencias de ejecución y desarrollo

Los paquetes necesarios para iniciar la aplicación no deberían mezclarse conceptualmente con pytest, Ruff o herramientas de documentación:

uv add fastapi
uv add --dev pytest ruff
uv remove fastapi

Después de añadir, eliminar o actualizar, revisa pyproject.toml y el diff de uv.lock. Un único cambio directo puede mover varias dependencias transitivas. No es necesariamente un error, pero merece la misma revisión que un cambio de código.

Los grupos de dependencias sirven para flujos opcionales, como documentación o pruebas de integración. Evita crear grupos sin una necesidad clara. Documenta cuáles instala la CI y comprueba los comandos en la versión de uv adoptada. Una convención pequeña y compartida suele ser más reproducible que una configuración muy flexible.

Elegir la versión de Python conscientemente

uv puede descargar y seleccionar intérpretes, mientras que requires-python sigue siendo el contrato de compatibilidad:

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

El resolvedor utiliza ese rango, así que no es una simple nota. Para establecer un intérprete habitual en el directorio de trabajo:

uv python install 3.12
uv python pin 3.12

No amplíes el rango sin pruebas. Un programa escrito con 3.12 puede usar sintaxis que 3.10 no entiende, y una dependencia puede haber abandonado versiones antiguas. Las bibliotecas que anuncian varias versiones necesitan una matriz de pruebas. El gestor elige intérpretes, pero no demuestra la compatibilidad del comportamiento.

Ejecutar comandos en un contexto previsible

uv run expone los ejecutables del entorno del proyecto y comprueba la sincronización cuando hace falta:

uv run python -m pytest
uv run ruff check .
uv run python -m analizador

La forma python -m pytest hace explícito qué intérprete ejecuta el módulo. Activar .venv puede resultar cómodo en una terminal, pero no debe ser un requisito oculto del build.

Para una herramienta aislada que no pertenece al proyecto, uvx puede crear un entorno temporal. Úsalo con criterio. Si una versión concreta de Ruff o de un generador modifica archivos versionados, fija o declara la herramienta para que el equipo y la CI obtengan resultados compatibles.

Actualizar dependencias sin sorpresas

Sincronizar no significa actualizar. uv sync reproduce la solución actual; una actualización deliberada debe generar un cambio revisable en el lockfile y pasar las pruebas.

uv lock --upgrade-package requests
uv sync
uv run pytest

Prefiere actualizaciones específicas y consulta las notas de versiones importantes. Antes de cruzar una versión principal, busca cambios incompatibles. La resolución debe ocurrir dentro de un cambio revisado, no por primera vez durante el despliegue. Producción debe consumir la decisión ya aprobada.

Si la resolución falla, identifica en el mensaje el rango de Python, las restricciones directas y las transitivas. Quitar todos los límites puede ocultar el conflicto y producir una combinación sin soporte. Averigua qué paquete vuelve imposibles las restricciones y decide si actualizarlo, sustituirlo o conservar temporalmente una versión anterior.

CI y despliegue reproducibles

La guía oficial para GitHub Actions presenta la acción mantenida por el proyecto y sus opciones actuales. El flujo habitual obtiene el repositorio, instala Python y uv, sincroniza dependencias y ejecuta lint y pruebas.

El caché solo debe mejorar el rendimiento. Un runner limpio tiene que funcionar cuando el caché está vacío. No versiones .venv ni copies un entorno entre sistemas operativos. El lockfile puede contemplar artefactos específicos por plataforma, pero una instalación ya creada no es portable.

En imágenes de contenedor, copiar primero los metadatos de dependencias puede aprovechar el caché de capas. Después se copia el código. Comprueba que el paquete local quede instalado cuando la aplicación lo importa y que el comando final use el entorno previsto.

Errores frecuentes al adoptar uv

  • Mantener requirements.txt, comandos de Poetry y uv indefinidamente sin elegir una fuente de verdad.
  • Editar uv.lock manualmente.
  • Ignorar un diff grande del lockfile porque solo se pidió un paquete directo.
  • Confundir uv sync con una actualización general.
  • Fijar un intérprete local incompatible con requires-python.
  • Ejecutar mediante uvx un generador sin versión cuyo resultado entra al repositorio.
  • Resolver las dependencias por primera vez en el servidor de producción.

Durante la migración, conserva el flujo anterior solamente durante un periodo corto de comparación. Una vez validados pruebas, comandos y despliegue, elimina las instrucciones antiguas o planifica esa eliminación. Dos fuentes de verdad que envejecen en paralelo son difíciles de depurar.

Lista de comprobación

Clona el repositorio en otro directorio y confirma que uv sync reconstruye el entorno. Verifica que .venv está ignorado, que pyproject.toml contiene dependencias directas justificadas, que uv.lock fue revisado y que el rango de Python coincide con la realidad. La documentación local y la CI deben usar los mismos comandos.

Por último, inicia la aplicación y ejecuta todas las pruebas sin paquetes globales. Esta comprobación encuentra imports accidentales, archivos ausentes y comandos que solo funcionaban en la máquina original. Ese camino verificable desde los metadatos hasta un proceso funcional, más que la velocidad por sí sola, es el argumento central para usar uv.