[!NOTE] Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.

UV en macOS: Gestión de versiones de Python, proyectos y herramientas

He pasado mi flujo de trabajo en Python a uv, ya que reemplaza a todas las herramientas que antes utilizaba para alternar entre pip, entornos virtuales, pip-tools, pipx y gestores de proyectos. Ahora un único ejecutable cubre la mayor parte de esas tareas.

Los flujos de trabajo siguen siendo diferentes. Un proyecto, un script de metadatos integrados, una herramienta CLI de uso único y una herramienta CLI instalada cuentan cada uno con su propio entorno y ciclo de vida. Esta guía muestra los comandos que utilizo y los límites que definen cada uno de ellos.

Inicio rápido

# Install uv with Homebrew
brew install uv

# Start a project
uv init example-app
cd example-app
uv add httpx
uv run python main.py

# Run an isolated CLI without installing it permanently
uvx ruff check .

# Run a script that declares PEP 723 dependencies
uv run fetch.py

TL;DR. Yo utilizo uv add, uv lock, uv sync, y uv run dentro de los proyectos; metadatos según PEP 723 para scripts autónomos. uvx para herramientas puntuales; y uv tool install para los comandos que deben permanecer activos PATH. En CI, --locked verifica que la metadatos del proyecto coincidan con uv.lock; --frozen Confía en el candado existente sin verificar su estado de actualidad.

Instalar uv con un único propietario

Homebrew es una vía de instalación muy práctica en macOS:

brew install uv
uv --version

Si Homebrew instaló uv, debería actualizarlo:

brew upgrade uv

uv self update Se utiliza para el método de instalación independiente de UV y está desactivado en las instalaciones a través del gestor de paquetes. No permita que dos instaladores compitan por el mismo ejecutable.

Comandos de identidad útiles:

command -v uv
uv python dir
uv tool dir
uv cache dir

Las instalaciones gestionadas de Python, las herramientas persistentes y las entradas de caché desechables disponen de directorios separados. El caché puede eliminarse y reconstruirse; no constituye una fuente de verdad.

Los cuatro límites del flujo de trabajo UV

Proyectos: declaraciones, resolución y entorno

Un proyecto de IA suele contener tres artefactos diferentes:

Entradas y estado derivado en un proyecto UV

Crea una aplicación e incluye runtime así como los requisitos de prueba:

uv init forecast-app
cd forecast-app

uv add httpx
uv add --group test pytest
uv run python main.py
uv run --group test pytest

Los plantillas actuales de aplicación UV generan main.py, pyproject.toml, README.md, y .python-version. Por defecto, no definen un sistema de compilación. Utilice uv init --lib para una biblioteca empaquetada con un src diseño y compilación backend.

uv run Revisa el proyecto, actualiza el mecanismo de bloqueo cuando es necesario, sincroniza las dependencias requeridas y ejecuta la orden. La primera operación del proyecto crea .venv y uv.lock cuando sea necesario; uv init En sí mismo, solo genera los archivos del proyecto.

Commit los datos de entrada, no el entorno

Cometer pyproject.toml, uv.lock, fuente, y un propósito intencional .python-version. Ignorar .venv y los cachés de UV.

El bloqueo registra una resolución válida en los marcadores y plataformas compatibles; no hace que las ruedas nativas sean idénticas en macOS, Linux, Intel y Apple Silicon. Es necesario probar cada plataforma de despliegue.

Bloqueo de la frescura: --locked no es --frozen

Por defecto, los comandos del proyecto pueden realizar actualizaciones. uv.lock cuando cambian las declaraciones.

Utilizar --locked para obligar a que el candado esté actualizado con la metadatos del proyecto:

uv lock --check
uv sync --locked
uv run --locked pytest

Si pyproject.toml y uv.lock

Utilizar --frozen ¡Solo cuando se desee intencionadamente que el UV utilice el bloqueo existente sin verificar si es el actual!

uv sync --frozen

Eso puede resultar útil en una fase de compilación controlada en la que el bloqueo ya ha sido validado, pero no constituye un detector de bloqueos obsoletos. uv sync De forma predeterminada es exacto y elimina los paquetes no necesarios. uv run utiliza una sincronización inexacta por defecto, a menos que --exact Se solicita.

Python gestionado: una solicitud de versión, no un binario universal

uv puede descargar y gestionar distribuciones de Python:

uv python install 3.12 3.13
uv python list --only-installed
uv python pin 3.12

las compilaciones gestionadas de CPython de uv provienen del python-build-standalone Proyecto: UV también es capaz de detectar interpretadores del sistema, Homebrew, pyenv, Conda y otros.

.python-version Se trata de una solicitud de versión detectada por UV y otras herramientas compatibles. requires-python en pyproject.toml Es el contrato de compatibilidad del proyecto. Mantengan ambos aspectos intencionados:

[project]
requires-python = ">=3.12,<3.14"

Fijación 3.12

Utilizar otro gestor de Python cuando un proyecto requiera una configuración de distribución o de compilación que uv no proporcione. uv puede seguir utilizando dicho intérprete a través de --python o mediante descubrimiento normal.

Elija entre uv run, uvx, y las herramientas instaladas

Elegir un entorno de herramientas para el proyecto: efímero o persistente

Herramientas acopladas al proyecto: uv run

Si pytest, mypy, un generador de código u otra herramienta debe importar el proyecto o utilizar sus complementos bloqueados, declárelo en un grupo de dependencias:

uv add --group lint ruff
uv run --group lint ruff check .

Ejecutando esa herramienta mediante uvx Isolaría dicho componente del proyecto y podría ocultar el paquete instalado o las extensiones que necesita.

Herramientas ad hoc: uvx

uvx es un alias de uv tool run. Crea un entorno aislado almacenado en la caché UV desechable:

uvx ruff@0.12.0 check .
uvx --from jupyterlab jupyter lab
uvx --with mkdocs-material mkdocs --help

Fije la versión de la herramienta en el proceso CI o en la documentación. La primera ejecución sin especificar versión seleccionará una versión actual, y las ejecuciones posteriores podrán reutilizar el estado del caché.

Ejecutables persistentes: uv tool install

Instalar una herramienta cuando los scripts que están fuera de su control necesitan ejecutar su comando. PATH, o cuando el manifiesto de la máquina lo posee intencionadamente:

uv tool install 'ruff==0.12.0'
uv tool list
uv tool upgrade ruff
uv tool uninstall ruff

Las herramientas persistentes siguen utilizando entornos aislados. No modifique manualmente dichos entornos con pip.

Scripts: convertir un único archivo en la unidad de lanzamiento

PEP 723 define los metadatos de los scripts en línea. Un ejecutor compatible puede leer el bloque de comentarios y crear un entorno aislado.

Anatomía de un script PEP 723

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "httpx>=0.27,<1",
# ]
# ///
import httpx


response = httpx.get("https://example.com", timeout=10)
response.raise_for_status()
print(response.status_code)

Ejecuta y edita metadatos con uv:

uv run fetch.py
uv add --script fetch.py rich
uv remove --script fetch.py rich

Texto sin formato especial python fetch.py Ignora los metadatos del comentario. Por lo tanto, el script depende de un ejecutor compatible, aun cuando la sintaxis de Python siga siendo válida.

Para un script que debe reproducir una resolución más adelante, se debe crear un bloqueo adyacente:

uv lock --script fetch.py
uv run --script fetch.py

Esto realiza la escritura. fetch.py.lock. Un exclude-newer La marca de tiempo puede restringir las fechas de distribución de los candidatos, pero su efecto es menor que el de una resolución fija y exacta, y no garantiza que el artefacto siga estando disponible.

Se debe utilizar un proyecto cuando varios archivos comparten dependencias, el código es importable como paquete, las pruebas requieren el estado del proyecto, o varios scripts deben moverse junto con él.

Archivos de requisitos: compatibilidad, no fallos

A requirements.txt El archivo puede contener entradas sueltas, pines exactos, hashes, restricciones, índices, URLs o un entorno compilado. Su reproductibilidad depende de cómo se generó y se consumió; el nombre del archivo por sí solo no indica nada.

Utilice la interfaz compatible con pip de uv sin necesidad de migrar:

uv venv
uv pip sync requirements.txt
uv run python app.py

uv pip sync hace que el entorno se ajuste al archivo, mientras que uv pip install -r Es aditivo.

Para una aplicación propia, una migración por fases puede resultar útil:

uv init --bare
uv add -r requirements.in
uv add --group test -r requirements-test.in
uv lock
uv sync --locked

Ejecuta todo el proceso de pruebas e implementación antes de eliminar los archivos antiguos. Si un sistema posterior sigue esperando el formato de pip, obténlo a partir del archivo uv lock ya validado:

uv export --format requirements.txt \
  --output-file requirements.txt

No se debe mantener uv.lock y una exportación editada manualmente con dos resoluciones competidoras.

Caché, índices y límites de la cadena de suministro

El caché UV mejora las instalaciones repetidas, pero sigue siendo reutilizable una sola vez:

uv cache prune
uv cache clean

Preferir prune para la limpieza de rutina. clean Elimina todas las entradas de caché y obliga a que se realicen descargas y compilaciones posteriores.

Un archivo de bloqueo mejora la reproductibilidad, pero no hace que las dependencias sean fiables. Revise las fuentes del paquete, la configuración del índice, las revisiones de Git, los servidores de compilación, las licencias y las credenciales. Mantenga la configuración del índice autenticada fuera de los archivos comprometidos, a menos que el repositorio almacene únicamente referencias no secretas a un mecanismo de credenciales aprobado.

Para los paquetes nativos, se debe registrar la arquitectura de despliegue y la disponibilidad del wheel de pruebas. De lo contrario, un resolutor podría recurrir a una compilación desde el código fuente, que requiere compiladores y bibliotecas del sistema que no están presentes en el entorno CI ni en producción.

Lista de verificación operativa compacta

Para cada proyecto:

  1. Definir requires-python y las dependencias directas en pyproject.toml2. Separe los recursos adicionales publicados de los grupos de dependencias locales.
  2. Haga commit. uv.lock; ignorar .venv y el estado del caché.
  3. Ejecutar herramientas acopladas al proyecto a través del entorno del mismo.
  4. Utilizar uv lock --check o --locked en el flujo de integración continua.

UV resulta de gran utilidad cuando estos límites de propiedad permanecen visibles. Un único binario puede gestionarlos todos sin convertirlos en un único entorno. Esa combinación —menos herramientas, sin pretender que cada flujo de trabajo sea idéntico— es la razón por la cual sigo utilizando UV como mi herramienta predeterminada para proyectos en Python en macOS.

Referencias