Files
gh-basher83-lunar-claude-pl…/skills/python-uv-scripts/SKILL.md
2025-11-29 18:00:18 +08:00

546 lines
13 KiB
Markdown

---
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
```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: team@example.com
"""
```
**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: 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:
```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: ${{ secrets.PROXMOX_TOKEN }}
```
### GitLab CI
```yaml
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](workflows/ci-cd-integration.md).
## Tools Available
### Script Validation
```bash
# Validate PEP 723 metadata
./tools/validate_script.py script.py
# Output:
# ✓ Valid PEP 723 metadata
# ✓ Python version specified
# ✓ Dependencies properly formatted
```
### Script Conversion
```bash
# 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
- [PEP 723 Specification](reference/pep-723-spec.md) - Complete inline metadata spec
- [Dependency Management](reference/dependency-management.md) - Version pinning strategies
- [Security Patterns](reference/security-patterns.md) - Secrets, validation, input sanitization
### Pattern Guides
- [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
- [Error Handling](patterns/error-handling.md) - Exception handling, logging
> **Note:** See [Common Patterns](#common-patterns) section above for quick access to these guides.
### Working Examples
- [NetBox API Client](examples/04-api-clients/netbox_client.py) - Production-ready API client with Infisical, validation, error handling, and Rich output
- [Cluster Health Checker](examples/03-production-ready/check_cluster_health_enhanced.py) - Production-ready monitoring script with Typer, Rich, and JSON output
### Anti-Patterns
- [When NOT to Use](anti-patterns/when-not-to-use.md) - Signs you need a proper project
- [Common Mistakes](anti-patterns/common-mistakes.md) - Pitfalls and how to avoid them
### Workflows
- [Team Adoption](workflows/team-adoption.md) - Rolling out uv scripts across teams
- [CI/CD Integration](workflows/ci-cd-integration.md) - GitHub Actions, GitLab CI
- [Testing Strategies](workflows/testing-strategies.md) - Inline tests, pytest integration
## 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
```python
# 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
```python
# 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
```python
#!/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