Claude Code Plugins

Community-maintained marketplace

Feedback

python-uv-scripts

@basher83/lunar-claude
0
0

>

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name python-uv-scripts
description Python single-file script development using uv and PEP 723 inline metadata. Prevents invalid patterns like [tool.uv.metadata]. Use when creating standalone Python utilities, converting scripts to uv format, managing script dependencies, implementing script testing, or establishing team standards for script development.

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

#!/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:

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

Convert Existing Script

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

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

When to Use This Skill

Activate this skill when:

  • Creating standalone Python utilities or automation scripts
  • Converting scripts from requirements.txt to uv format
  • Adding dependencies to existing single-file scripts
  • Implementing testing for utility scripts
  • Establishing team standards for script development
  • Reviewing scripts for security or best practices
  • Setting up CI/CD for script execution
  • Creating infrastructure automation tools (like cluster health checkers)

Core Concepts

What is PEP 723?

PEP 723 defines inline script metadata for Python files:

# /// 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)

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

Mode 2: Project Mode (For larger scripts)

uv run script.py  # Uses pyproject.toml

Mode 3: No Dependencies

#!/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:

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

Error:

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:

# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Purpose: Testing automation
Team: DevOps
Author: team@example.com
"""

Valid tool.uv fields (if needed):

# /// 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

Current version (basic):

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

Enhanced with uv (production-ready):

#!/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

Pattern: JSON API interaction with structured output

Best Practices from This Repository

1. Security Patterns

Don't hardcode secrets:

# ❌ BAD
password = "super_secret"

# ✅ GOOD - Use environment variables
import os
password = os.getenv("PROXMOX_PASSWORD")
if not password:
    raise ValueError("PROXMOX_PASSWORD not set")

Better - Use keyring:

# /// script
# dependencies = ["keyring>=24.0.0"]
# ///
import keyring
password = keyring.get_password("proxmox", "api_user")

Best - Use Infisical (following repository pattern):

# /// script
# dependencies = ["infisical-python>=2.3.3"]
# ///
from infisical import InfisicalClient

client = InfisicalClient()
password = client.get_secret("PROXMOX_PASSWORD", path="/matrix")

See patterns/security-patterns.md for complete guide.

2. Version Pinning Strategy

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

# /// 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.

3. Team Standards

File naming:

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

Shebang pattern:

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

Documentation template:

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

Purpose: cluster-monitoring
Team: infrastructure
Author: devops@spaceships.work

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:

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.

5. Testing Patterns

Inline testing (for simple scripts):

#!/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.

When NOT to Use Single-File Scripts

See 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:

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

Common Patterns

Pattern: CLI Application

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

import typer
from rich import print

app = typer.Typer()

@app.command()
def hello(name: str):
    """Greet someone"""
    print(f"[green]Hello {name}![/green]")

if __name__ == "__main__":
    app()

See patterns/cli-applications.md.

Pattern: API Client

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

import httpx
import os

def get_proxmox_nodes(api_url: str, token: str):
    """Fetch Proxmox cluster nodes"""
    headers = {"Authorization": f"PVEAPIToken={token}"}

    with httpx.Client(verify=False) as client:
        response = client.get(f"{api_url}/nodes", headers=headers)
        response.raise_for_status()
        return response.json()

if __name__ == "__main__":
    api_url = os.getenv("PROXMOX_API_URL")
    token = os.getenv("PROXMOX_TOKEN")

    nodes = get_proxmox_nodes(api_url, token)
    for node in nodes['data']:
        print(f"{node['node']}: {node['status']}")

See patterns/api-clients.md.

Pattern: Data Processing

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

import polars as pl
import sys

def analyze_logs(log_file: str):
    """Analyze log file for errors"""
    df = pl.read_csv(log_file)

    errors = df.filter(pl.col("level") == "ERROR")
    print(f"Total errors: {len(errors)}")

    by_component = errors.group_by("component").count()
    print("\nErrors by component:")
    print(by_component)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: analyze_logs.py <log_file>")
        sys.exit(1)

    analyze_logs(sys.argv[1])

See patterns/data-processing.md.

Pattern: System Automation

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

import psutil
import sys

def check_disk_space(threshold: int = 80):
    """Check if disk usage exceeds threshold"""
    usage = psutil.disk_usage('/')
    percent = usage.percent

    if percent >= threshold:
        print(f"WARNING: Disk usage at {percent}%", file=sys.stderr)
        sys.exit(1)

    print(f"OK: Disk usage at {percent}%")

if __name__ == "__main__":
    threshold = int(sys.argv[1]) if len(sys.argv) > 1 else 80
    check_disk_space(threshold)

See patterns/system-automation.md.

CI/CD Integration

GitHub Actions

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: ${{ secrets.PROXMOX_TOKEN }}

GitLab CI

cluster-health:
  image: ghcr.io/astral-sh/uv:python3.11-bookworm-slim
  script:
    - uv run --script tools/check_cluster_health.py
  only:
    - schedules

See workflows/ci-cd-integration.md.

Tools Available

Script Validation

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

# Output:
# ✓ Valid PEP 723 metadata
# ✓ Python version specified
# ✓ Dependencies properly formatted

Script Conversion

# Convert requirements.txt-based script to uv
./tools/convert_to_uv.py old_script.py

# Creates:
# - old_script_uv.py with inline dependencies
# - Preserves original script

Progressive Disclosure

For deeper knowledge:

Reference Documentation

Pattern Guides

Working Examples

  • NetBox API Client - Production-ready API client with Infisical, validation, error handling, and Rich output
  • Examples README - Complete examples directory with progressive complexity

Anti-Patterns

Workflows

Related Skills

  • Ansible Best Practices - Many Ansible modules could be standalone uv scripts
  • Proxmox Infrastructure - Validation tools use this pattern
  • NetBox + PowerDNS Integration - API interaction scripts

Quick Reference

Shebang Options

# Standard script execution
#!/usr/bin/env -S uv run --script

# Quiet mode (suppress uv output)
#!/usr/bin/env -S uv run --script --quiet

# With Python version
#!/usr/bin/env -S uv run --script --python 3.11

Common Dependencies

# CLI applications
"typer>=0.9.0"        # Modern CLI framework
"click>=8.0.0"        # Alternative CLI framework
"rich>=13.0.0"        # Rich text and formatting

# API clients
"httpx>=0.27.0"       # Modern async HTTP client
"requests>=2.31.0"    # Traditional HTTP client

# Data processing
"polars>=0.20.0"      # Fast dataframe library
"pandas>=2.0.0"       # Traditional dataframe library

# Infrastructure
"ansible>=11.1.0"     # Automation (from this repo)
"infisical-python>=2.3.3"  # Secrets (from this repo)

# System automation
"psutil>=5.9.0"       # System monitoring

Metadata Template

#!/usr/bin/env -S uv run --script --quiet
# /// script
# requires-python = ">=3.11"
# dependencies = [
#   # Add dependencies here
# ]
# ///
"""
One-line description

Purpose: describe-purpose
Team: team-name
Author: email@example.com

Usage:
    python script.py [OPTIONS]

Examples:
    python script.py --help
"""

Best Practices Summary

  1. Always specify Python version - requires-python = ">=3.11"
  2. Pin dependencies appropriately - Use >=X.Y.Z for utilities
  3. Add metadata in docstrings - Put team info, purpose, and author in module docstring
  4. Include comprehensive docstrings - Document purpose, usage, and examples
  5. Handle errors gracefully - Use try/except with clear messages
  6. Validate inputs - Check arguments before processing
  7. Use quiet mode - --quiet flag for production scripts
  8. Keep it focused - Single file, single purpose
  9. Test inline - Add --test flag for simple validation
  10. Secure secrets - Never hardcode, use env vars or keyring