Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:00:18 +08:00
commit 765529cd13
69 changed files with 18291 additions and 0 deletions

View File

@@ -0,0 +1,209 @@
# API Client Patterns
Patterns for building API clients with uv scripts.
## Basic GET Request
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx>=0.27.0",
# ]
# ///
import httpx
response = httpx.get("https://api.github.com/users/octocat")
response.raise_for_status()
data = response.json()
print(f"Name: {data['name']}")
```
## Authenticated Requests
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx>=0.27.0",
# ]
# ///
import httpx
import os
import sys
api_token = os.getenv("API_TOKEN")
if not api_token:
print("Error: API_TOKEN not set", file=sys.stderr)
sys.exit(1)
headers = {"Authorization": f"Bearer {api_token}"}
response = httpx.get(
"https://api.example.com/data",
headers=headers,
timeout=10.0
)
response.raise_for_status()
print(response.json())
```
## POST with JSON
```python
import httpx
data = {
"name": "example",
"status": "active"
}
response = httpx.post(
"https://api.example.com/resources",
json=data,
headers={"Authorization": f"Bearer {token}"},
timeout=10.0
)
response.raise_for_status()
result = response.json()
print(f"Created: {result['id']}")
```
## Query Parameters
```python
import httpx
params = {
"q": "python",
"sort": "stars",
"order": "desc"
}
response = httpx.get(
"https://api.github.com/search/repositories",
params=params
)
response.raise_for_status()
repos = response.json()
```
## Error Handling
```python
import httpx
import sys
try:
with httpx.Client(timeout=10.0) as client:
response = client.get("https://api.example.com/data")
response.raise_for_status()
data = response.json()
except httpx.HTTPStatusError as e:
status = e.response.status_code
if status == 401:
print("Error: Unauthorized - check API key", file=sys.stderr)
elif status == 404:
print("Error: Resource not found", file=sys.stderr)
elif status >= 500:
print(f"Error: Server error ({status})", file=sys.stderr)
else:
print(f"Error: HTTP {status}", file=sys.stderr)
sys.exit(1)
except httpx.RequestError as e:
print(f"Error: Request failed - {type(e).__name__}", file=sys.stderr)
sys.exit(1)
```
## Retry Logic
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx>=0.27.0",
# "tenacity>=8.2.0",
# ]
# ///
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def fetch_data(url: str):
"""Fetch data with automatic retry."""
response = httpx.get(url, timeout=10.0)
response.raise_for_status()
return response.json()
data = fetch_data("https://api.example.com/data")
```
## Pagination
```python
import httpx
def fetch_all_pages(base_url: str, headers: dict):
"""Fetch all pages from paginated API."""
all_results = []
next_url = base_url
with httpx.Client(headers=headers, timeout=10.0) as client:
while next_url:
response = client.get(next_url)
response.raise_for_status()
data = response.json()
all_results.extend(data["results"])
# Get next page URL
next_url = data.get("next")
return all_results
```
## Rate Limiting
```python
import httpx
import time
def fetch_with_rate_limit(urls: list[str], requests_per_second: int = 2):
"""Fetch URLs respecting rate limit."""
delay = 1.0 / requests_per_second
results = []
for url in urls:
response = httpx.get(url)
response.raise_for_status()
results.append(response.json())
time.sleep(delay)
return results
```
## Complete Example
For a complete API client template, see: `assets/templates/api-client.py`
## Best Practices
- Always set timeouts (default: 10 seconds)
- Use `with httpx.Client()` for multiple requests
- Handle specific HTTP status codes (401, 404, 500)
- Don't log sensitive data (tokens, responses)
- Use environment variables for credentials
- Implement retry logic for transient failures
- Respect rate limits

View File

@@ -0,0 +1,129 @@
# CLI Application Patterns
Patterns for building command-line applications with uv scripts.
## Basic CLI with Typer
```python
#!/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 main(
name: str = typer.Argument(..., help="Your name"),
greeting: str = typer.Option("Hello", "--greeting", "-g"),
):
"""Greet someone."""
print(f"[green]{greeting}, {name}![/green]")
if __name__ == "__main__":
app()
```
## Multiple Subcommands
```python
import typer
app = typer.Typer()
@app.command()
def create(name: str):
"""Create a new resource."""
print(f"Creating: {name}")
@app.command()
def delete(name: str):
"""Delete a resource."""
print(f"Deleting: {name}")
if __name__ == "__main__":
app()
```
Usage:
```bash
./script.py create foo
./script.py delete bar
```
## File Input/Output
```python
import typer
from pathlib import Path
def process_file(
input_file: Path = typer.Argument(..., exists=True),
output: Path = typer.Option(None, "--output", "-o"),
):
"""Process a file."""
content = input_file.read_text()
# Process
result = content.upper()
if output:
output.write_text(result)
print(f"Written to: {output}")
else:
print(result)
```
## Progress Bars
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "rich>=13.0.0",
# ]
# ///
from rich.progress import track
import time
for item in track(range(100), description="Processing..."):
time.sleep(0.01) # Simulate work
```
## Formatted Tables
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "rich>=13.0.0",
# ]
# ///
from rich.console import Console
from rich.table import Table
console = Console()
table = Table(title="Results")
table.add_column("Name", style="cyan")
table.add_column("Status", style="green")
table.add_row("Task 1", "✓ Complete")
table.add_row("Task 2", "⏳ Pending")
console.print(table)
```
For complete template, see: `assets/templates/cli-app.py`

View File

@@ -0,0 +1,54 @@
# Data Processing Patterns
> **Status**: 🚧 Placeholder - Content in development
## Overview
Patterns for data analysis, ETL, and processing using Polars, pandas, and other data libraries in UV single-file
scripts.
## Topics to Cover
- [ ] Polars patterns (recommended for performance)
- [ ] Pandas alternatives
- [ ] CSV/Excel processing
- [ ] JSON data manipulation
- [ ] Data validation and cleaning
- [ ] Aggregation and transformation
- [ ] Memory-efficient processing
## Quick Example
```python
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = ["polars>=0.20.0"]
# ///
import polars as pl
def analyze_csv(file_path: str):
df = pl.read_csv(file_path)
# Basic analysis
summary = df.describe()
print(summary)
# Filter and aggregate
result = (
df.filter(pl.col("value") > 100)
.groupby("category")
.agg(pl.col("value").mean())
)
print(result)
```
## TODO
This file will be expanded to include:
- Complete Polars patterns
- Performance optimization techniques
- Large file processing strategies
- Data validation patterns
- Export formats and options

View File

@@ -0,0 +1,198 @@
# Error Handling Patterns
Best practices for error handling in uv scripts.
## Exit Codes
Always use appropriate exit codes:
- `0` - Success
- `1` - General error
- `2` - Invalid usage
```python
import sys
if len(sys.argv) < 2:
print("Usage: script.py <input>", file=sys.stderr)
sys.exit(2) # Invalid usage
try:
result = process()
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1) # General error
# Success
sys.exit(0)
```
## Try-Except Pattern
```python
import sys
def main():
try:
# Operations that might fail
data = fetch_data()
result = process(data)
save(result)
except FileNotFoundError as e:
print(f"File not found: {e}", file=sys.stderr)
sys.exit(1)
except ValueError as e:
print(f"Invalid data: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Unexpected error: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
```
## HTTP Error Handling
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx>=0.27.0",
# ]
# ///
import httpx
import sys
try:
response = httpx.get("https://api.example.com", timeout=10.0)
response.raise_for_status()
data = response.json()
except httpx.HTTPStatusError as e:
print(f"HTTP {e.response.status_code} error", file=sys.stderr)
sys.exit(1)
except httpx.RequestError as e:
print(f"Request failed: {type(e).__name__}", file=sys.stderr)
sys.exit(1)
except httpx.TimeoutException:
print("Request timed out", file=sys.stderr)
sys.exit(1)
```
## File Operation Errors
```python
from pathlib import Path
import sys
def read_config(path: Path):
"""Read configuration file with error handling."""
try:
if not path.exists():
raise FileNotFoundError(f"Config not found: {path}")
if not path.is_file():
raise ValueError(f"Not a file: {path}")
return path.read_text()
except PermissionError:
print(f"Permission denied: {path}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error reading config: {e}", file=sys.stderr)
sys.exit(1)
```
## Subprocess Errors
```python
import subprocess
import sys
try:
result = subprocess.run(
["command", "arg"],
capture_output=True,
text=True,
check=True
)
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Command failed with exit code {e.returncode}", file=sys.stderr)
print(f"Error output: {e.stderr}", file=sys.stderr)
sys.exit(1)
except FileNotFoundError:
print("Command not found", file=sys.stderr)
sys.exit(1)
```
## Validation Errors
```python
import sys
def validate_input(value: str) -> int:
"""Validate and convert input."""
if not value:
print("Error: Empty value", file=sys.stderr)
sys.exit(2)
try:
number = int(value)
except ValueError:
print(f"Error: Not a number: {value}", file=sys.stderr)
sys.exit(2)
if number < 0:
print("Error: Must be non-negative", file=sys.stderr)
sys.exit(2)
return number
```
## Graceful Cleanup
```python
import sys
from pathlib import Path
def main():
temp_file = Path("/tmp/data.tmp")
try:
# Create temporary file
temp_file.write_text("data")
# Process
result = process(temp_file)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
finally:
# Always cleanup
if temp_file.exists():
temp_file.unlink()
```
## Summary
- Always write errors to `stderr`
- Use specific exception types
- Provide helpful error messages
- Use appropriate exit codes
- Clean up resources in `finally` blocks
- Don't expose secrets in error messages

View File

@@ -0,0 +1,32 @@
# Security Patterns for UV Single-File Scripts
> **Status**: 🚧 Placeholder - Content in development
## Overview
Security patterns and best practices for handling secrets, authentication, and input validation in UV single-file
Python scripts.
## Topics to Cover
- [ ] Infisical secrets management integration
- [ ] Keyring for credential storage
- [ ] Environment variable security
- [ ] Input validation and sanitization
- [ ] API token handling
- [ ] SSH key management
- [ ] Avoiding hardcoded credentials
## Quick Reference
For now, see the main security section in [../reference/security-patterns.md](../reference/security-patterns.md).
## TODO
This file will be expanded to include:
- Complete Infisical integration patterns
- Best practices for secret rotation
- Multi-environment secret management
- Security checklist for scripts
- Common security vulnerabilities and fixes

View File

@@ -0,0 +1,61 @@
# System Automation Patterns
> **Status**: 🚧 Placeholder - Content in development
## Overview
Patterns for system administration, monitoring, and automation using psutil, subprocess, and system libraries in UV
single-file scripts.
## Topics to Cover
- [ ] psutil for system monitoring
- [ ] subprocess for command execution
- [ ] File system operations
- [ ] Process management
- [ ] SSH remote execution
- [ ] Cron/scheduled task integration
- [ ] Log file analysis
## Quick Example
```python
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = ["psutil>=5.9.0", "rich>=13.0.0"]
# ///
import psutil
from rich.console import Console
from rich.table import Table
console = Console()
def show_disk_usage():
table = Table(title="Disk Usage")
table.add_column("Device", style="cyan")
table.add_column("Mount", style="magenta")
table.add_column("Used", style="yellow")
table.add_column("Free", style="green")
for partition in psutil.disk_partitions():
usage = psutil.disk_usage(partition.mountpoint)
table.add_row(
partition.device,
partition.mountpoint,
f"{usage.percent}%",
f"{usage.free / (1024**3):.2f} GB"
)
console.print(table)
```
## TODO
This file will be expanded to include:
- Complete psutil monitoring patterns
- Safe subprocess execution
- SSH automation patterns
- System health checks
- Automated maintenance tasks