Cómo actualizar paquetes con uv: actualizaciones individuales, restricciones, uv.lock y reversión

Por qué uv sync no actualiza los paquetes: ejemplos de uv lock --upgrade-package, restricciones con uv add, diferencias entre --locked y --frozen, verificación y reversión de cambios.

Para actualizar una dependencia en un proyecto uv, primero actualiza el archivo de bloqueo con uv lock --upgrade-package 包名 y después instala y verifica con uv sync --locked. Si el rango declarado no permite la versión deseada, modifica primero las restricciones de pyproject.toml.

El error más habitual es confundir «sincronizar el entorno» con «buscar la última versión». Si el paquete no cambia después de ejecutar uv sync, normalmente uv está respetando el archivo de bloqueo existente.

Esta guía está dirigida a proyectos Python que ya tienen un pyproject.toml. Los ejemplos usan PowerShell; los comandos principales de uv también funcionan en Linux y macOS. Se utilizan requests y pytest para que puedas probarlos en un directorio independiente, sin conectarte a una API de modelos. La documentación se comprobó el 11 de octubre de 2026. No se ha verificado aquí la compatibilidad de ningún proyecto de IA concreto después de actualizarlo.

Identifica qué capa quieres actualizar

«Actualizar uv» puede referirse a tres tipos de objetos distintos. Identificar primero el objetivo evita actualizar la herramienta y preguntarse por qué las dependencias del proyecto siguen igual.

Objetivo Operación habitual Efecto principal
El ejecutable de uv Actualizar uv mediante su canal de instalación original Versión del gestor de paquetes
Una dependencia del proyecto uv lock --upgrade-package requests Resolución registrada en el archivo de bloqueo
Rango de versiones permitido uv add "requests>=2.32,<3" Declaración del proyecto, archivo de bloqueo y entorno
Todas las dependencias del proyecto uv lock --upgrade Todas las dependencias bloqueadas que admitan actualización
Una herramienta instalada con uv tool uv tool upgrade 工具名 Entorno aislado de la herramienta

No uses uv tool upgrade para actualizar requests dentro del proyecto. Tampoco supongas que actualizar el ejecutable de uv actualiza automáticamente los paquetes de .venv. Las herramientas instaladas y las dependencias del proyecto se mantienen por separado; consulta la guía de herramientas de uv.

Qué controlan pyproject.toml, uv.lock y .venv

Un cambio de dependencias plantea tres preguntas: qué versiones permite el proyecto, cuáles selecciona la resolución y cuáles están realmente instaladas en este equipo.

Archivo o directorio Función ¿Se incluye en Git?
pyproject.toml Declarar dependencias directas y rangos permitidos Sí
uv.lock Guardar los resultados exactos de la resolución Sí
.python-version Registrar la versión de Python elegida para el proyecto Normalmente
.venv Entorno instalado en este equipo No

Por ejemplo, el proyecto puede declarar:

1
2
3
4
5
6
7
[project]
name = "dependency-demo"
version = "0.1.0"
requires-python = ">=3.12,<3.13"
dependencies = [
    "requests>=2.31,<3",
]

Esta configuración permite un rango de versiones de requests. No pide instalar la versión más reciente de ese rango en cada ejecución.

Si uv.lock ya fija una versión compatible, una sincronización normal suele conservarla. Esto reduce las sorpresas de un proyecto que funcionaba ayer y falla al reinstalarlo hoy. Consulta la documentación de bloqueo y sincronización para conocer el mecanismo.

Practica una actualización individual en otro directorio

Primero comprueba que las herramientas estén disponibles:

1
2
uv --version
git --version

Elige un nombre de directorio que todavía no exista para no escribir los archivos de práctica en un repositorio en uso. El siguiente ejemplo utiliza un proyecto de scripts, sin configurar un backend de construcción de paquetes Python.

1
2
3
4
5
6
uv init --bare --python 3.12 uv-update-demo
Set-Location uv-update-demo
uv python pin 3.12
uv add "requests>=2.31,<3"
uv add --dev pytest
uv sync --locked

Si falta la versión de Python necesaria, uv puede tener que descargar un intérprete. En una red restringida, resuelve primero los problemas de descarga o detección del intérprete antes de diagnosticar conflictos de dependencias. Las reglas de selección de Python se explican en la documentación oficial de intérpretes.

Crea main.py:

1
2
3
4
5
6
7
from importlib.metadata import version
import requests

request = requests.Request("GET", "https://example.com/").prepare()
print("requests:", version("requests"))
print("method:", request.method)
print("url:", request.url)

Este código prepara una petición, pero no la envía por la red. Comprueba que el paquete se pueda importar y muestra la versión realmente instalada en el entorno actual.

1
2
uv run --locked python main.py
uv tree --locked

Después registra un estado inicial para la práctica:

1
2
3
4
git init
git status --short
git add pyproject.toml uv.lock .python-version main.py
git commit -m "Record dependency baseline"

Antes del commit, comprueba que .venv no esté en el área de preparación. Si todavía no has configurado tu identidad de Git, conserva copias de los archivos; los comandos de reversión posteriores requieren un commit existente.

Actualiza un paquete y revisa los cambios

Ejecuta lo siguiente en el directorio del proyecto que acabas de crear:

1
2
3
4
uv lock --upgrade-package requests
git diff -- uv.lock
uv sync --locked
uv run --locked python main.py

Separar la resolución de la instalación permite revisar el archivo de bloqueo antes de modificar el entorno de trabajo. Si prefieres hacerlo en una sola operación, puedes usar uv sync --upgrade-package requests.

Una «actualización individual» toma ese paquete como objetivo; no garantiza que cambie una sola entrada del archivo de bloqueo. La nueva versión puede necesitar dependencias transitivas diferentes, y el resolvedor debe encontrar una combinación compatible con todo el proyecto.

Al revisar las diferencias, comprueba:

  • Si ha cambiado requests.
  • Si se han añadido o eliminado dependencias transitivas.
  • Si los orígenes de descarga siguen siendo los previstos.
  • Si otra restricción mantiene el paquete en su versión anterior.

Un proyecto de práctica recién creado normalmente ya habrá seleccionado una versión disponible actualmente. Por tanto, una nueva actualización sin diferencias puede ser normal y no indica que el comando haya fallado.

Para comprobar la instalación, utiliza el intérprete del proyecto:

1
2
uv run --locked python -c "import sys; print(sys.executable)"
uv run --locked python -c "from importlib.metadata import version; print(version('requests'))"

La primera salida debería apuntar al entorno del proyecto. Si el editor muestra otra versión, revisa primero la ruta de Python que tiene seleccionada.

Por qué la actualización puede conservar una versión antigua

Supongamos que el proyecto declara:

1
2
3
dependencies = [
    "requests==2.31.0",
]

Una restricción exacta solo permite esa versión. --upgrade-package no ignora la declaración del proyecto.

Si has evaluado la compatibilidad y decides permitir versiones posteriores, cambia el rango explícitamente:

1
2
3
uv add "requests>=2.32,<3"
git diff -- pyproject.toml uv.lock
uv run --locked python main.py

Por defecto, uv add actualiza la declaración, el archivo de bloqueo y el entorno, por lo que este paso ya puede instalar una nueva versión. Ejecútalo en una rama independiente; no es una consulta de solo lectura.

Si solo quieres evaluar una versión concreta, declara esa versión exacta y pruébala. No elimines todos los límites superiores únicamente para que la resolución termine: un límite existente puede representar una incompatibilidad conocida.

Otros paquetes, las versiones de Python y las condiciones de plataforma también pueden restringir el rango. Si hay un conflicto, identifica los requisitos contradictorios en el mensaje de error. Consulta la documentación de gestión de dependencias para modificar declaraciones y grupos.

Reserva una tarea de mantenimiento para actualizarlo todo

Para actualizar todo el proyecto:

1
2
3
4
uv lock --upgrade
git diff --stat
git diff -- uv.lock
uv sync --locked

Una actualización completa corresponde a una tarea de mantenimiento de dependencias; evita mezclarla con un commit destinado únicamente a modificar texto de una página. Cuanto mayor sea el cambio, más difícil será identificar el paquete que causa un fallo.

Empieza por una dependencia de la aplicación y ejecuta las comprobaciones de aceptación; después trata las herramientas de desarrollo por separado. Los proyectos con extensiones nativas, entornos de ejecución GPU o backends de inferencia también requieren revisar bibliotecas del sistema y controladores. El archivo de bloqueo registra la resolución de paquetes, pero no sustituye las pruebas en el equipo real.

Cuándo usar –locked y –frozen

Ambos parámetros aparecen a menudo en despliegues, pero realizan comprobaciones diferentes.

Comando Comportamiento Uso
uv lock --check Comprobar que el archivo de bloqueo coincide con la declaración Comprobación antes del commit
uv sync --locked Exigir un archivo de bloqueo actualizado y sincronizar Despliegue y reproducción
uv run --locked python main.py Exigir un archivo de bloqueo actualizado y ejecutar Verificación habitual
uv sync --frozen Usar el archivo existente sin comprobar si está actualizado Flujos que ya validan el archivo en otro paso

Si cambias la declaración y olvidas actualizar el archivo de bloqueo, --locked ayuda a detectar la discrepancia. Omitir esa comprobación con --frozen no demuestra que la nueva declaración se haya aplicado.

También debes tener en cuenta la limpieza del entorno: uv sync sincroniza de forma exacta por defecto y elimina los paquetes que no aparecen en el archivo de bloqueo. Por eso, un paquete de depuración instalado manualmente en .venv puede desaparecer en la siguiente sincronización. Declara las herramientas de desarrollo que quieras conservar mediante uv add --dev.

Comprueba un comportamiento clave después de actualizar

Crea test_main.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests


def test_prepare_request_keeps_query_parameter():
    prepared = requests.Request(
        "GET",
        "https://example.com/search",
        params={"q": "hello world"},
    ).prepare()
    assert prepared.method == "GET"
    assert prepared.url == "https://example.com/search?q=hello+world"

Ejecuta:

1
2
3
4
uv lock --check
uv run --locked pytest -q
uv run --locked python main.py
git diff --check

Esta prueba cubre el comportamiento concreto de codificar parámetros de una petición. No demuestra que funcionen la conexión de red, el proxy, TLS o las interfaces de la aplicación. Los proyectos reales deben verificar sus propias rutas críticas, como resultados de análisis documental, operaciones de base de datos o estructuras de respuesta de API.

Si el proyecto utiliza MinerU para analizar documentos, elige un PDF fijo y compara el número de páginas, las tablas y las referencias de imágenes antes y después de actualizar. Conservar una muestra pequeña como entrada de regresión aporta más evidencia que comprobar únicamente que import funciona.

Cómo recuperarse de una actualización fallida

Conserva primero los registros de error y las diferencias, y comprueba si hay trabajo ajeno a esta actualización. Los siguientes comandos descartan los cambios sin commit de estos dos archivos. Úsalos solo si todos esos cambios pertenecen a esta actualización.

1
2
3
4
git diff -- pyproject.toml uv.lock
git restore --source=HEAD -- pyproject.toml uv.lock
uv sync --locked
uv run --locked pytest -q

Restaurar juntos la declaración y el archivo de bloqueo evita contradicciones entre ambos. Vuelve a ejecutar las pruebas después de sincronizar para confirmar que has recuperado un estado funcional, no solo archivos aparentemente iguales.

Si la actualización ya tiene un commit, localiza primero uno cuyo funcionamiento esté confirmado y restaura las versiones correspondientes o revierte el commit de actualización. No copies directamente la .venv de otra persona: pueden diferir las rutas, los binarios de plataforma y la versión del intérprete.

Revertir dependencias tampoco deshace automáticamente migraciones de base de datos ni cambios de datos producidos al ejecutar la aplicación. Si la actualización afecta a formatos de datos, necesitas el procedimiento de copia de seguridad y recuperación de la propia aplicación.

Qué hacer si solo tienes requirements.txt

Decide primero si quieres conservar el flujo basado en requirements o migrar formalmente a un proyecto uv. No mezcles ambos objetivos en un único comando de actualización.

Para conservar el flujo actual, instala en un entorno virtual separado:

1
2
uv venv
uv pip install -r requirements.txt

Si requirements ya fija versiones exactas, este comando de instalación no elimina esas restricciones. Para migrar al flujo de proyectos, inicializa el proyecto en una rama de migración e importa las dependencias:

1
2
3
uv init --bare
uv add -r requirements.txt
uv lock --check

Importar un archivo generado por pip freeze puede convertir dependencias transitivas en declaraciones directas. Después de migrar, distingue los paquetes que realmente usa la aplicación de los que llegan como dependencias de otros. Los índices privados, las instalaciones editables y las condiciones de plataforma requieren una revisión aparte; consulta la guía oficial de migración.

Exporta dependencias para despliegues que todavía usan pip

Si aún no puedes trasladar todo el proyecto a uv, exporta desde el archivo de bloqueo:

1
uv export --locked --format requirements.txt --no-dev --output-file requirements.txt

Considera este archivo un artefacto derivado del archivo de bloqueo. Después de cambiar dependencias, actualiza el proyecto y su archivo de bloqueo antes de exportar de nuevo, en lugar de mantener manualmente dos listas de versiones.

El proyecto del ejemplo no se empaqueta a sí mismo. En aplicaciones instalables también debes comprobar si la exportación incluye el propio proyecto o referencias a rutas locales. El despliegue debe disponer del código fuente correspondiente; copiar solo requirements puede no ser suficiente. Las opciones se describen en la documentación oficial de exportación.

Referencia rápida para resolver problemas

Síntoma Primera comprobación Qué hacer
La versión no cambia después de sync Ya existe una versión compatible bloqueada Solicitar explícitamente una actualización individual
Sigue una versión antigua después de upgrade Restricciones exactas o de otros paquetes Revisar la resolución y evaluar cambios en la declaración
Funciona en terminal, falla la importación en el editor Ruta del intérprete Python Seleccionar la .venv del proyecto
Archivo de bloqueo correcto, instalación fallida Red, certificados, disco, wheels de plataforma Guardar el error y localizar la fase de descarga o construcción
El despliegue indica un archivo de bloqueo desactualizado Si declaración y archivo se incluyeron en el mismo commit Actualizar y validar el archivo en una rama de desarrollo
Desaparecen herramientas temporales tras sincronizar Si están declaradas como dependencias dev Gestionarlas con uv add --dev

Una actualización está completa cuando las declaraciones son claras, el archivo de bloqueo es coherente, el entorno instalado es correcto y los comportamientos críticos de la aplicación superan la verificación. Una vez identificado el objetivo, empieza por un paquete y conserva las diferencias y una vía de recuperación.