Claude
Skills
Sign in
Back

python-uv-scripts

Included with Lifetime
$97 forever

Python single-file script development using uv and PEP 723 inline metadata, preventing invalid patterns like [tool.uv.metadata].

Generalassets

What this skill does


# Python Single-File Scripts with uv

Expert guidance for creating production-ready, self-contained Python scripts using uv's inline dependency management
(PEP 723).

## Quick Start

### Create Your First uv Script

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

import httpx
from rich import print

response = httpx.get("https://api.github.com")
print(f"[green]Status: {response.status_code}[/green]")
```

Make it executable:

```bash
chmod +x script.py
./script.py  # uv automatically installs dependencies
```

### Convert Existing Script

```bash
# Add inline metadata to existing script
./tools/convert_to_uv.py existing_script.py

# Validate PEP 723 metadata
./tools/validate_script.py script.py
```

## Core Concepts

### What is PEP 723?

**PEP 723** defines inline script metadata for Python files:

```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "package>=1.0.0",
# ]
# ///
```

**Benefits:**

- ✅ Dependencies live with the code
- ✅ No separate `requirements.txt`
- ✅ Reproducible execution
- ✅ Version constraints included
- ✅ Self-documenting

### uv Script Execution Modes

**Mode 1: Inline Dependencies** (Recommended for utilities)

```python
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["httpx"]
# ///
```

**Mode 2: Project Mode** (For larger scripts)

```bash
uv run script.py  # Uses pyproject.toml
```

### Mode 3: No Dependencies

```python
#!/usr/bin/env -S uv run
# Standard library only
```

## Critical Anti-Patterns: What NOT to Do

### ❌ NEVER Use [tool.uv.metadata]

**WRONG** - This will cause errors:

```python
# /// script
# requires-python = ">=3.11"
# [tool.uv.metadata]        # ❌ THIS DOES NOT WORK
# purpose = "testing"
# ///
```

**Error**:

```text
error: TOML parse error at line 3, column 7
unknown field `metadata`
```

**Why**: `[tool.uv.metadata]` is not part of PEP 723 and is not supported by uv.

**CORRECT** - Use Python docstrings for metadata:

```python
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Purpose: Testing automation
Team: DevOps
Author: [email protected]
"""
```

**Valid `tool.uv` fields** (if needed):

```python
# /// script
# requires-python = ">=3.11"
# dependencies = []
# [tool.uv]
# exclude-newer = "2025-01-01T00:00:00Z"  # For reproducibility
# ///
```

## Real-World Examples from This Repository

### Example 1: Cluster Health Checker

See [examples/03-production-ready/check_cluster_health_enhanced.py](examples/03-production-ready/check_cluster_health_enhanced.py)

**Current version** (basic):

```python
#!/usr/bin/env python3
import subprocess
# Manual dependency installation required
```

**Enhanced with uv** (production-ready):

```python
#!/usr/bin/env -S uv run --script --quiet
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "rich>=13.0.0",
#   "typer>=0.9.0",
# ]
# ///
"""
Purpose: Cluster health monitoring
Team: Infrastructure
"""

import typer
from rich.console import Console
from rich.table import Table
```

### Example 2: CEPH Health Monitor

See [examples/03-production-ready/ceph_health.py](examples/03-production-ready/ceph_health.py)

Pattern: JSON API interaction with structured output

## Best Practices from This Repository

### 1. Security Patterns

See [reference/security-patterns.md](reference/security-patterns.md) for complete security guide including:

- Secrets management (environment variables, keyring, Infisical)
- Input validation
- Dependency security
- File operations security
- Command execution security

### 2. Version Pinning Strategy

Following this repository's approach (from `pyproject.toml`):

```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   "httpx>=0.27.0",      # Minimum version for compatibility
#   "rich>=13.0.0",       # Known good version
#   "ansible>=11.1.0",    # Match project requirements
# ]
# ///
```

**Pinning levels:**

- `>=X.Y.Z` - Minimum version (most flexible)
- `~=X.Y.Z` - Compatible release (patch updates only)
- `==X.Y.Z` - Exact version (most strict)

See [reference/dependency-management.md](reference/dependency-management.md).

### 3. Team Standards

**File naming:**

```bash
check_cluster_health.py    # ✅ Descriptive, snake_case
validate_template.py       # ✅ Action-oriented
cluster.py                 # ❌ Too generic
```

**Shebang pattern:**

```python
#!/usr/bin/env -S uv run --script --quiet
# --quiet suppresses uv's own output
```

**Documentation template:**

```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Check Proxmox cluster health

Purpose: cluster-monitoring
Team: infrastructure
Author: [email protected]

Usage:
    python check_cluster_health.py [--node NODE] [--json]

Examples:
    python check_cluster_health.py --node foxtrot
    python check_cluster_health.py --json
"""
```

### 4. Error Handling Patterns

Following Ansible best practices from this repository:

```python
import sys
import subprocess

def run_command(cmd: str) -> str:
    """Execute command with proper error handling"""
    try:
        result = subprocess.run(
            cmd.split(),
            capture_output=True,
            text=True,
            check=True
        )
        return result.stdout
    except subprocess.CalledProcessError as e:
        print(f"Error: Command failed: {cmd}", file=sys.stderr)
        print(f"  {e.stderr}", file=sys.stderr)
        sys.exit(1)
    except FileNotFoundError:
        print(f"Error: Command not found: {cmd.split()[0]}", file=sys.stderr)
        sys.exit(1)
```

See [patterns/error-handling.md](patterns/error-handling.md).

### 5. Testing Patterns

**Inline testing** (for simple scripts):

```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///

def validate_ip(ip: str) -> bool:
    """Validate IP address format"""
    import re
    pattern = r'^(\d{1,3}\.){3}\d{1,3}$'
    return bool(re.match(pattern, ip))

# Inline tests
if __name__ == "__main__":
    import sys

    # Run tests if --test flag provided
    if len(sys.argv) > 1 and sys.argv[1] == "--test":
        assert validate_ip("192.168.1.1") == True
        assert validate_ip("256.1.1.1") == False
        print("All tests passed!")
        sys.exit(0)

    # Normal execution
    print(validate_ip("192.168.3.5"))
```

See [workflows/testing-strategies.md](workflows/testing-strategies.md).

## When NOT to Use Single-File Scripts

See [anti-patterns/when-not-to-use.md](anti-patterns/when-not-to-use.md) for details.

**Use a proper project instead when:**

- ❌ Script exceeds 500 lines
- ❌ Multiple modules/files needed
- ❌ Complex configuration management
- ❌ Requires packaging/distribution
- ❌ Shared library code across multiple scripts
- ❌ Web applications or long-running services

**Example - Too Complex for Single File:**

```python
# This should be a uv project, not a script:
# - 15+ dependencies
# - Database models
# - API routes
# - Background workers
# - Configuration management
# - Multiple environments
```

## Common Patterns

See pattern guides for complete examples:

- [CLI Applications](patterns/cli-applications.md) - Typer, Click, argparse patterns
- [API Clients](patterns/api-clients.md) - httpx, requests, authentication
- [Data Processing](patterns/data-processing.md) - Polars, pandas, analysis
- [System Automation](patterns/system-automation.md) - psutil, subprocess, system admin

## CI/CD Integration

### GitHub Actions

```yaml
name: Run Health Checks

on:
  schedule:
    - cron: '0 */6 * * *'  # Every 6 hours

jobs:
  health-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Check cluster health
        run: |
          uv run --script tools/check_cluster_health.py --json
        env:
          PROXMOX_TOKEN

Related in General