Logotipo de Bitdoze

uv run: ejecuta scripts de Python sin gestionar dependencias

Aprende a usar uv run para ejecutar scripts de Python al instante. Sin venv ni pip install. Cubre dependencias con --with, metadatos PEP 723 y scripts con shebang.

Dragos

Actualizado Publicado 47 min de lectura

uv run: ejecuta scripts de Python sin gestionar dependencias

Ejecuta cualquier script de Python con dependencias en un solo comando. Sin entorno virtual, sin pip install, sin requirements.txt. uv run se encarga de todo: resuelve las dependencias, crea un entorno aislado, ejecuta tu script y guarda el resultado en caché para que las reejecuciones sean rápidas.

uv es un gestor de paquetes de Python escrito en Rust, con licencia Apache-2.0/MIT, creado por Astral (ahora una empresa de OpenAI). En el momento de escribir esto, la versión actual es la 0.12.x. Sigue siendo completamente de código abierto y el ritmo de publicaciones del proyecto no se ha ralentizado desde la adquisición.

¿Nuevo en uv?

Consulta primero Cómo empezar con uv para instalar uv y entender lo básico.

¿Por qué usar uv run para scripts de Python?

El flujo de trabajo tradicional en Python para ejecutar un script con dependencias externas es este:

  1. Crear un entorno virtual
  2. Activarlo
  3. Instalar las dependencias con pip
  4. Ejecutar el script
  5. Desactivarlo y, opcionalmente, limpiarlo

Con uv run, toda esa secuencia se reduce a una línea:

bash
uv run --with requests myscript.py

uv resuelve la dependencia, crea un entorno aislado (que queda en caché para reutilizarse en ejecuciones posteriores), ejecuta el script y listo. El entorno no se borra tras cada ejecución: se almacena en ~/.cache/uv, así que las ejecuciones repetidas con las mismas dependencias son casi instantáneas. Simplemente no tienes que pensar en ello.

Ejecutar scripts sin dependencias (uv run)

El caso más sencillo: un script que solo usa la biblioteca estándar de Python.

python
# test_basic.py
import os
import sys
import json

def system_info():
    info = {
        "python_version": sys.version,
        "platform": sys.platform,
        "user_home": os.path.expanduser("~"),
        "current_directory": os.getcwd()
    }
    print(json.dumps(info, indent=2))

if __name__ == "__main__":
    system_info()

Ejecútalo:

bash
uv run test_basic.py

Salida esperada:

json
{
  "python_version": "3.13.5 (main, Jun 11 2025, 15:30:20)",
  "platform": "linux",
  "user_home": "/home/username",
  "current_directory": "/home/username/scripts"
}

¿Ejecutando dentro de un directorio de proyecto?

Si ejecutas uv run script.py dentro de un directorio que contiene un pyproject.toml, uv instalará primero las dependencias del proyecto actual, aunque tu script no las necesite. Usa uv run --no-project script.py para omitir la detección del proyecto y ejecutar el script de forma aislada. Nota: el flag --no-project debe ir antes del nombre del script.

Ejecutar scripts con dependencias externas (uv run –with)

Aquí es donde uv realmente brilla. Crea un script que necesite paquetes de terceros y especifícalos en la línea de comandos:

python
# test_api.py
import requests
import json
from datetime import datetime

def test_github_api():
    """Fetch GitHub API data for the astral-sh org"""
    try:
        response = requests.get("https://api.github.com/users/astral-sh")
        data = response.json()

        print(f"✅ API Response Status: {response.status_code}")
        print(f"🏢 Organization: {data.get('name', 'N/A')}")
        print(f"📍 Location: {data.get('location', 'N/A')}")
        print(f"👥 Public Repos: {data.get('public_repos', 0)}")
        print(f"⏰ Tested at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

    except requests.exceptions.RequestException as e:
        print(f"❌ API request failed: {e}")
    except KeyError as e:
        print(f"❌ Unexpected API response format: {e}")

if __name__ == "__main__":
    test_github_api()

Ejecútalo con el flag --with:

bash
uv run --with requests test_api.py

Salida esperada (el valor de public_repos cambia con el tiempo; vuelve a ejecutarlo para ver el número actual):

text
✅ API Response Status: 200
🏢 Organization: Astral
📍 Location: United States of America
👥 Public Repos: 82
⏰ Tested at: 2026-08-23 10:15:42

Puedes especificar varias dependencias:

bash
uv run --with requests --with pandas --with matplotlib data_analysis.py

O usar restricciones de versión:

bash
uv run --with 'requests>=2.31.0,<3.0.0' --with 'pandas>=2.0.0' test_script.py

Si obtienes un ModuleNotFoundError, la causa más común es un flag --with que falta o una errata en el nombre del paquete.

Para un ejemplo real de monitorización de API, consulta nuestro script comprobador masivo de URLs creado con uv.

Usar metadatos en línea en el script (PEP 723)

Para los scripts que vas a ejecutar más de una vez, incrustar la información de las dependencias directamente en el archivo es más limpio que pasar flags --with cada vez. El estándar PEP 723 de Python define un formato de metadatos en línea que uv lee automáticamente.

El formato de la cabecera PEP 723

Los metadatos en línea usan un bloque de comentarios especial al principio de tu archivo Python:

python
# /// script
# dependencies = [
#   "requests>=2.31.0",
#   "rich>=13.0.0"
# ]
# requires-python = ">=3.11"
# [tool.uv]
# exclude-newer = "2026-01-01T00:00:00Z"
# ///

Esto es lo que hace cada campo:

dependencies: lista todos los paquetes de Python que necesita tu script, con sintaxis estilo pip:

  • "requests>=2.31.0": versión mínima
  • "pandas>=2.0.0,<3.0.0": rango de versiones
  • "rich": la más reciente disponible
  • "django==4.2.7": versión exacta fijada

Este campo debe estar presente aunque tu script no tenga dependencias externas. En ese caso, usa dependencies = [].

requires-python: especifica el requisito de versión de Python con sintaxis PEP 440:

  • ">=3.11": Python 3.11 o superior
  • ">=3.11,<3.14": solo Python 3.11, 3.12 o 3.13

Sección [tool.uv]: configuración opcional específica de uv:

  • exclude-newer: solo tiene en cuenta paquetes publicados antes de esta marca de tiempo (formato RFC 3339). Mejora la reproducibilidad al evitar que una publicación futura de un paquete cambie tu resolución de dependencias.

Ejemplo completo: analizador de perfiles de GitHub

python
# /// script
# dependencies = [
#   "requests>=2.31.0",
#   "rich>=13.0.0",
#   "click>=8.0.0"
# ]
# requires-python = ">=3.11"
# [tool.uv]
# exclude-newer = "2026-01-01T00:00:00Z"
# ///

import requests
import click
from rich.console import Console
from rich.table import Table

console = Console()

@click.command()
@click.option('--username', prompt='GitHub username', help='GitHub username to analyze')
def analyze_github_user(username):
    """Analyze a GitHub user's profile and repositories"""

    with console.status(f"[bold green]Fetching data for {username}..."):
        try:
            user_response = requests.get(f"https://api.github.com/users/{username}")
            user_response.raise_for_status()
            user_data = user_response.json()

            repos_response = requests.get(f"https://api.github.com/users/{username}/repos")
            repos_response.raise_for_status()
            repos_data = repos_response.json()

        except requests.exceptions.RequestException as e:
            console.print(f"[bold red]Error fetching data: {e}")
            return

    console.print(f"\n[bold blue]GitHub User Analysis: {username}[/bold blue]")
    console.print(f"Name: {user_data.get('name', 'N/A')}")
    console.print(f"Bio: {user_data.get('bio', 'N/A')}")
    console.print(f"Public Repos: {user_data.get('public_repos', 0)}")
    console.print(f"Followers: {user_data.get('followers', 0)}")

    table = Table(title=f"Top Repositories for {username}")
    table.add_column("Repository", style="cyan")
    table.add_column("Stars", style="magenta")
    table.add_column("Language", style="green")
    table.add_column("Description", style="yellow")

    top_repos = sorted(repos_data, key=lambda x: x.get('stargazers_count', 0), reverse=True)[:10]

    for repo in top_repos:
        table.add_row(
            repo['name'],
            str(repo.get('stargazers_count', 0)),
            repo.get('language', 'N/A'),
            (repo.get('description', 'N/A') or 'N/A')[:50] + "..."
        )

    console.print(table)

if __name__ == "__main__":
    analyze_github_user()

Guárdalo como github_analyzer.py y ejecútalo:

bash
uv run github_analyzer.py

uv lee los metadatos en línea, instala requests, rich y click automáticamente y después ejecuta el script.

Más ejemplos de PEP 723

Análisis de datos

python
# /// script
# dependencies = [
#   "pandas>=2.0.0",
#   "matplotlib>=3.7.0"
# ]
# requires-python = ">=3.10"
# ///

import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv('data.csv')
plt.plot(data['x'], data['y'])
plt.title("Data Analysis")
plt.show()

Ejecutar con: uv run data_analysis.py

Pruebas de API

python
# /// script
# dependencies = [
#   "httpx>=0.27.0",
#   "pytest>=8.0.0"
# ]
# requires-python = ">=3.10"
# [tool.uv]
# exclude-newer = "2026-01-01T00:00:00Z"
# ///

import httpx
import pytest

def test_health_endpoint():
    response = httpx.get("https://api.example.com/health")
    assert response.status_code == 200

def test_users_endpoint():
    response = httpx.get("https://api.example.com/users")
    assert response.status_code == 200
    assert len(response.json()) > 0

Ejecutar con: uv run api_tests.py

Generador de informes

python
# /// script
# dependencies = [
#   "pandas>=2.0.0",
#   "rich>=13.0.0"
# ]
# requires-python = ">=3.10"
# ///

import pandas as pd
from rich.console import Console
from rich.table import Table

console = Console()

df = pd.read_csv("sales.csv")
summary = df.groupby("product").agg({"amount": "sum", "quantity": "sum"}).reset_index()

table = Table(title="Sales Summary")
table.add_column("Product", style="cyan")
table.add_column("Revenue", style="green")
table.add_column("Units Sold", style="magenta")

for _, row in summary.iterrows():
    table.add_row(row["product"], f"${row['amount']:,.2f}", str(int(row["quantity"])))

console.print(table)

Ejecutar con: uv run report.py

Configurar un índice de paquetes privado

Los antiguos campos index-url y extra-index-url de [tool.uv] están obsoletos. El enfoque moderno usa tablas [[tool.uv.index]]:

python
# /// script
# dependencies = ["requests>=2.31.0"]
# requires-python = ">=3.10"
# [[tool.uv.index]]
# url = "https://pypi.example.com/simple"
# ///

También puedes añadir índices desde la CLI al gestionar scripts:

bash
uv add --script example.py --index "https://pypi.example.com/simple" 'requests<3'

Para sobrescribir el índice por defecto, usa --default-index en lugar del obsoleto --index-url.

Ciclo de vida del script: init → add → run → lock → audit

Editar a mano el bloque # /// funciona, pero uv ahora tiene comandos de primera clase para gestionar los metadatos de los scripts. Es el camino más rápido de la idea al script en ejecución.

1. Crear un script nuevo

bash
uv init --script healthcheck.py --python 3.12

Esto crea healthcheck.py con la cabecera PEP 723 ya incluida.

2. Añadir dependencias

bash
uv add --script healthcheck.py 'httpx>=0.27' 'rich'

uv actualiza los metadatos en línea del archivo. Sin edición manual de TOML.

3. Ejecutarlo

bash
uv run healthcheck.py https://example.com

4. Bloquear para reproducibilidad

bash
uv lock --script healthcheck.py

Esto crea healthcheck.py.lock, un archivo de bloqueo adyacente que fija las versiones exactas de las dependencias. Comprueba que existe:

bash
ls healthcheck.py.lock

5. Ejecutar solo con las dependencias bloqueadas

bash
uv run --locked healthcheck.py

Esto falla si el archivo de bloqueo no existe o está desactualizado, que es exactamente lo que quieres en CI.

6. Auditar CVE conocidos

bash
uv audit --script healthcheck.py

Esto comprueba tus dependencias bloqueadas contra bases de datos de vulnerabilidades conocidas. Nota: el script debe estar bloqueado primero; uv audit sobre un script sin bloquear dará error.

7. Inspeccionar el árbol de dependencias

bash
uv tree --script healthcheck.py

8. Eliminar una dependencia

bash
uv remove --script healthcheck.py rich

Este ciclo de vida (init -> add -> run -> lock -> audit) convierte el «editar TOML a mano» en un flujo de trabajo gestionado con reproducibilidad y auditoría de seguridad integradas.

Crear scripts ejecutables con un shebang de uv

Para los scripts que ejecutas con frecuencia, añade un shebang para hacerlos directamente ejecutables. La línea #!/usr/bin/env -S uv run --script le indica al sistema que use uv para ejecutar el script. También hay un alias corto: -s en lugar de --script.

python
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
#   "httpx>=0.27.0",
#   "typer>=12.0.0"
# ]
# requires-python = ">=3.11"
# ///

import httpx
import typer
from typing import Optional

app = typer.Typer()

@app.command()
def check_website(
    url: str = typer.Argument(..., help="Website URL to check"),
    timeout: Optional[int] = typer.Option(10, help="Request timeout in seconds")
):
    """Check if a website is up and running"""

    if not url.startswith(('http://', 'https://')):
        url = f"https://{url}"

    try:
        with httpx.Client(timeout=timeout) as client:
            response = client.get(url)

        if response.status_code == 200:
            typer.echo(f"✅ {url} is UP (Status: {response.status_code})")
            typer.echo(f"Response time: {response.elapsed.total_seconds():.2f}s")
        else:
            typer.echo(f"⚠️  {url} returned status {response.status_code}")

    except httpx.RequestError as e:
        typer.echo(f"❌ {url} is DOWN - {e}")
    except httpx.TimeoutException:
        typer.echo(f"❌ {url} timed out after {timeout} seconds")

if __name__ == "__main__":
    app()

Hazlo ejecutable y ejecútalo:

bash
chmod +x website_checker.py
./website_checker.py github.com

Gestionar las versiones de Python en los scripts

Puedes especificar qué versión de Python usar en cualquier ejecución de un script:

bash
# Run with Python 3.12
uv run --python 3.12 test_script.py

# Run with Python 3.13
uv run --python 3.13 test_script.py

Si la versión solicitada no está instalada, uv la descarga automáticamente. No hace falta instalación manual. ¿Necesitas instalar Python en tu sistema primero? Consulta nuestra guía sobre cómo instalar y gestionar versiones de Python.

También puedes fijar la versión en los metadatos en línea:

python
# /// script
# requires-python = ">=3.11"
# dependencies = ["aiohttp>=3.9"]
# ///

import asyncio
import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        "https://httpbin.org/delay/1",
        "https://httpbin.org/delay/2",
        "https://httpbin.org/delay/3"
    ]

    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)

    print(f"Fetched {len(results)} URLs successfully!")

if __name__ == "__main__":
    asyncio.run(main())

Nota: asyncio forma parte de la biblioteca estándar de Python — no es un paquete de PyPI y no debe aparecer en dependencies.

Variables de entorno y secretos (archivos .env)

Los scripts que llaman a API suelen necesitar secretos. En lugar de escribirlos directamente en el código, usa --env-file:

bash
uv run --env-file .env api_probe.py

Tu archivo .env:

text
API_KEY=sk-abc123
API_BASE_URL=https://api.example.com

Tu script los lee con os.environ:

python
import os

api_key = os.environ["API_KEY"]
base_url = os.environ.get("API_BASE_URL", "https://api.default.com")

Para desactivar la carga de .env (por ejemplo, en CI, donde defines las variables de entorno de otra forma), pasa --no-env-file.

No subas nunca los archivos .env

Añade .env a tu .gitignore de inmediato. Los secretos en el control de versiones son una brecha de seguridad esperando a ocurrir.

Stdin y scripts remotos

Puedes canalizar scripts directamente a uv por stdin:

bash
echo 'print("hello from stdin")' | uv run -

O usar la sintaxis heredoc:

bash
uv run - <<'EOF'
import sys
print(f"Running on Python {sys.version}")
EOF

uv run también acepta una URL HTTP(S): descarga y ejecuta el script:

bash
uv run https://example.com/scripts/healthcheck.py

Advertencia de seguridad para scripts remotos

Ejecutar un script desde una URL descarga y ejecuta código arbitrario. uv instalará automáticamente las dependencias que el script declare en su cabecera PEP 723. Ejecuta solo scripts remotos de fuentes en las que confíes. Esta función también está deshabilitada en algunos entornos corporativos y de CI.

Web scraping y conversión a Markdown

Un caso de uso práctico: extraer una página web y convertirla a Markdown limpio. Esta es una versión reducida — para scraping de nivel producción a escala, considera la plataforma de web scraping de Bright Data. Más información sobre web scraping con BrightData MCP.

python
# /// script
# dependencies = [
#   "requests>=2.31.0",
#   "beautifulsoup4>=4.13.0",
#   "markdownify>=0.14.0",
#   "typer>=12.0.0",
#   "rich>=13.0.0"
# ]
# requires-python = ">=3.10"
# ///

import requests
import typer
from bs4 import BeautifulSoup
from markdownify import markdownify as md
from rich.console import Console
from rich.panel import Panel
import re

console = Console()
app = typer.Typer()

def clean_markdown(text: str) -> str:
    text = re.sub(r'\n\s*\n\s*\n', '\n\n', text)
    return text.strip()

@app.command()
def scrape(
    url: str = typer.Argument(..., help="URL to scrape"),
    output: str = typer.Option(None, "--output", "-o", help="Output file"),
    selector: str = typer.Option(None, "--selector", "-s", help="CSS selector"),
):
    """Scrape a webpage and convert to markdown."""
    if not url.startswith(('http://', 'https://')):
        url = f"https://{url}"

    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
    }

    response = requests.get(url, headers=headers, timeout=10)
    response.raise_for_status()

    soup = BeautifulSoup(response.content, 'html.parser')

    for tag in soup(["script", "style", "nav", "footer", "header", "aside"]):
        tag.decompose()

    if selector:
        content = soup.select_one(selector)
    else:
        content = soup.find('article') or soup.find('main') or soup.find('body')

    if not content:
        console.print("[bold red]No content found")
        return

    markdown = clean_markdown(md(str(content), heading_style='ATX', bullets='*'))

    if output:
        with open(output, 'w') as f:
            f.write(markdown)
        console.print(f"[bold green]✅ Saved to {output}")
    else:
        preview = markdown[:2000] + "..." if len(markdown) > 2000 else markdown
        console.print(Panel(preview, title="Markdown Output", border_style="green"))

if __name__ == "__main__":
    app()

Uso:

bash
# Scrape and preview
uv run web_scraper.py https://example.com

# Save to file
uv run web_scraper.py https://blog.example.com --output article.md

# Extract specific content via CSS selector
uv run web_scraper.py https://docs.example.com --selector "article"

Buenas prácticas para los scripts de uv

  • Usa metadatos en línea (PEP 723) para cualquier script que ejecutes más de una vez
  • Especifica siempre requires-python para evitar sorpresas en distintos sistemas
  • Usa restricciones de versión: fija las versiones mayores para evitar cambios que rompan el código
  • Usa uv lock --script para ejecuciones reproducibles, sobre todo en CI
  • Revisa el bloque # /// antes de ejecutar scripts compartidos por otros (ver la sección de seguridad más abajo)
  • Gestiona los errores correctamente: las peticiones de red, la E/S de archivos y las llamadas a API fallan
  • Usa --env-file para los secretos en lugar de incrustar claves de API en tus scripts

Consideraciones de seguridad para scripts PEP 723

Los scripts PEP 723 instalan y ejecutan automáticamente las dependencias declaradas en el bloque # ///. Es cómodo, pero también es un vector para código malicioso, sobre todo porque muchas herramientas de análisis de composición de software (SCA) todavía no escanean los metadatos en línea.

Revisa antes de ejecutar

Antes de ejecutar un script PEP 723 de una fuente no confiable (un gist de GitHub, una entrada de blog, el fragmento de un colega), lee el bloque # /// script. Comprueba que los nombres de las dependencias no sean typosquatting (por ejemplo, requets en lugar de requests). Para los scripts que mantienes, usa uv lock --script y uv audit --script para detectar CVE conocidos.

Solución de problemas con uv run

ModuleNotFoundError

La causa más común: un flag --with que falta o una lista dependencies ausente o vacía en los metadatos en línea.

Solución: añade el flag --with en la línea de comandos, o añade el paquete al array dependencies de tu bloque # /// script. Recuerda que dependencies debe estar presente aunque esté vacío (dependencies = []).

El script se ejecuta con las dependencias del proyecto

Si ejecutas uv run script.py dentro de un directorio con un pyproject.toml, uv instala primero las dependencias del proyecto actual. Normalmente no es lo que quieres para scripts independientes.

Solución: añade --no-project antes del nombre del script:

bash
uv run --no-project script.py

Nota: los scripts con metadatos PEP 723 en línea ignoran automáticamente el proyecto que los rodea; --no-project solo es necesario para scripts sin metadatos en línea.

Autenticación en un índice privado

Si tus dependencias provienen de un PyPI privado (Azure Artifactory, AWS CodeArtifact, etc.), configura el índice en tus metadatos en línea:

python
# [[tool.uv.index]]
# url = "https://pkgs.dev.azure.com/myorg/_packaging/myfeed/pypi/simple/"

O pásalo por la CLI: uv run --index "https://..." script.py. Para las credenciales, usa uv auth login o define la variable de entorno UV_INDEX.

La caché crece demasiado

uv guarda en caché los entornos y los wheels en ~/.cache/uv. Con el tiempo puede crecer, sobre todo si ejecutas scripts con conjuntos de dependencias muy distintos.

Comprobar el tamaño:

bash
uv cache size --human

Limpieza:

bash
uv cache clean       # remove all cached packages
uv cache prune       # remove unused cache entries
Ejecuciones reproducibles en CI

Para una resolución de dependencias determinista en CI, bloquea primero el script y ejecútalo después con --locked:

bash
uv lock --script my_script.py
uv run --locked my_script.py

--locked falla si el archivo de bloqueo no existe o no coincide con los metadatos en línea. Usa --frozen para omitir la resolución por completo y usar lo que haya en el archivo de bloqueo (más rápido, pero no se actualizará si los metadatos cambiaron).

Beneficios de rendimiento

Astral afirma que uv es entre 10 y 100 veces más rápido que las herramientas tradicionales de gestión de paquetes de Python. La mejora exacta depende del escenario (instalaciones en frío frente a reejecuciones en caché, número de dependencias, latencia de red), pero la diferencia se nota en la práctica, sobre todo en pipelines de CI y en el desarrollo iterativo.

Donde más se nota:

  • Pipelines de CI/CD: compilaciones más rápidas significan ciclos de feedback más rápidos
  • Flujos de desarrollo: ejecuta scripts sin esperar a que se configure el entorno
  • Experimentación en ciencia de datos: cambia rápido entre conjuntos de bibliotecas
  • Administración de sistemas: usa conjuntos de herramientas distintos por script sin conflictos

Casos de uso comunes

Pruebas y monitorización de API

bash
# Quick API health check
uv run --with requests api_health_check.py

# Test API with different HTTP methods
uv run --with httpx --with typer api_tester.py --method POST --url https://api.example.com

Consulta nuestro script comprobador masivo de URLs con uv para un ejemplo completo de monitorización.

Procesamiento y análisis de datos

bash
# Process CSV files
uv run --with pandas --with matplotlib data_processor.py input.csv

# Web scraping and content conversion
uv run --with beautifulsoup4 --with requests --with markdownify web_scraper.py https://example.com

Administración de sistemas

bash
# Server monitoring
uv run --with psutil --with click server_monitor.py

# Log analysis
uv run --with click --with rich log_analyzer.py /var/log/app.log

Prototipado y experimentación

bash
# Test new libraries quickly
uv run --with fastapi --with uvicorn prototype_api.py

# Content extraction and conversion
uv run --with beautifulsoup4 --with markdownify --with typer content_converter.py

Ejecutar herramientas CLI empaquetadas con uvx

Si necesitas ejecutar una herramienta CLI empaquetada (no un archivo de script), usa uvx en lugar de uv run:

bash
uvx ruff check .
uvx httpie GET https://api.example.com
uvx black --check src/

uvx es la forma abreviada de uv tool run: instala la herramienta en un entorno aislado y la ejecuta. Úsalo para herramientas como ruff, black, httpie, mypy, etc. Usa uv run para tus propios archivos de script.

Conclusión

uv run elimina la fricción de la gestión de dependencias de Python para los scripts. Tanto si estás probando API, procesando datos, haciendo scraping de páginas web o prototipando, escribes el script y lo ejecutas: uv se encarga del resto.

  • Un solo comando para ejecutar cualquier script con dependencias: sin venv, sin pip
  • Los metadatos en línea PEP 723 mantienen las dependencias dentro del archivo del script
  • uv init --script + uv add --script + uv lock --script para un ciclo de vida gestionado
  • --env-file para los secretos, --locked para la reproducibilidad en CI, uv audit para la seguridad
  • Entre 10 y 100 veces más rápido que las herramientas tradicionales (benchmarks de Astral)

Cuando tu script crezca hasta convertirse en algo más grande, explora los mejores frameworks web de Python para crear aplicaciones completas. ¿Listo para contenedorizar? Aprende a ejecutar aplicaciones Python en Docker. Y cuando estés listo para desplegar, despliega tus proyectos uv con Dokploy y Railpack.

Artículos relacionados