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,373 @@
# Anti-Patterns: Common Mistakes with uv Scripts
This document lists common mistakes when creating uv scripts and how to avoid them.
## Critical Mistakes
### ❌ Using [tool.uv.metadata]
**WRONG**:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = []
# [tool.uv.metadata] # ❌ THIS DOES NOT WORK
# purpose = "testing"
# team = "devops"
# ///
```
**Error**:
```text
error: TOML parse error at line 4, column 7
|
4 | [tool.uv.metadata]
| ^^
unknown field `metadata`
```
**Why**: `[tool.uv.metadata]` is not part of PEP 723 and is not supported by uv.
**CORRECT**: Use docstrings for metadata:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Purpose: Testing automation
Team: DevOps
Author: team@example.com
"""
```
**NOTE**: `[tool.uv]` (without `.metadata`) IS valid for fields like `exclude-newer`. See reference/pep-723-spec.md.
### ❌ Adding Custom TOML Fields
**WRONG**:
```python
# /// script
# requires-python = ">=3.11"
# author = "me" # ❌ INVALID
# version = "1.0.0" # ❌ INVALID
# description = "test" # ❌ INVALID
# dependencies = []
# ///
```
**CORRECT**: Only use `requires-python` and `dependencies` at the top level:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = []
# ///
"""
Author: me
Version: 1.0.0
Description: test
"""
```
### ❌ Hardcoded Secrets
**WRONG**:
```python
API_KEY = "sk-1234567890abcdef" # ❌ NEVER DO THIS
PASSWORD = "super_secret_password" # ❌ NEVER DO THIS
```
**CORRECT**: Use environment variables:
```python
import os
import sys
API_KEY = os.getenv("API_KEY")
if not API_KEY:
print("Error: API_KEY environment variable not set", file=sys.stderr)
sys.exit(1)
```
**BETTER**: Use Infisical (following repo pattern):
```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "infisical-python>=2.3.3",
# ]
# ///
from infisical import InfisicalClient
client = InfisicalClient()
api_key = client.get_secret("API_KEY", path="/production")
```
### ❌ Missing Error Handling
**WRONG**:
```python
import httpx
response = httpx.get("https://api.example.com") # ❌ No error handling
data = response.json()
```
**CORRECT**:
```python
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 error: {e.response.status_code}", file=sys.stderr)
sys.exit(1)
except httpx.RequestError as e:
print(f"Request failed: {e}", file=sys.stderr)
sys.exit(1)
```
## When NOT to Use Single-File Scripts
### ❌ Complex Applications
Don't use single-file scripts when:
- **Script exceeds 500 lines** → Use a proper uv project
- **Multiple modules needed** → Use a proper uv project
- **Shared code across scripts** → Use a proper uv project with shared library
- **Web applications** → Use a proper uv project (Flask/FastAPI/Django)
- **Long-running services** → Use a proper uv project
- **Complex configuration** → Use a proper uv project with config files
**Example - Too Complex**:
```python
# This should be a uv project, not a script:
# - 15+ dependencies
# - Database models
# - API routes
# - Background workers
# - Multiple configuration files
# - 1000+ lines of code
```
### ❌ Heavy Dependencies
**WRONG**: Using heavy ML/data libraries in scripts:
```python
# /// script
# dependencies = [
# "tensorflow>=2.15.0", # ❌ Too heavy for script
# "torch>=2.1.0", # ❌ Too heavy for script
# "transformers>=4.35.0", # ❌ Too heavy for script
# ]
# ///
```
**Why**: These create very large environments. Use a proper project instead.
**OK**: Lightweight data processing:
```python
# /// script
# dependencies = [
# "polars>=0.20.0", # ✓ Reasonable for scripts
# "httpx>=0.27.0", # ✓ Reasonable for scripts
# ]
# ///
```
## Common Syntax Mistakes
### ❌ Missing # on TOML Lines
**WRONG**:
```python
# /// script
requires-python = ">=3.11" # ❌ Missing # at start
dependencies = [] # ❌ Missing # at start
# ///
```
**CORRECT**:
```python
# /// script
# requires-python = ">=3.11" # ✓ Each line starts with #
# dependencies = [] # ✓ Each line starts with #
# ///
```
### ❌ Wrong Marker Format
**WRONG**:
```python
# /// scripts # ❌ Wrong: "scripts" not "script"
# requires-python = ">=3.11"
# ///
# // script # ❌ Wrong: "//" not "///"
# requires-python = ">=3.11"
# //
# /// script # ❌ Wrong: No closing marker
# requires-python = ">=3.11"
```
**CORRECT**:
```python
# /// script # ✓ Exactly "/// script"
# requires-python = ">=3.11"
# /// # ✓ Exactly "///"
```
## Dependency Management Mistakes
### ❌ No Version Constraints
**WRONG**:
```python
# /// script
# dependencies = [
# "httpx", # ❌ No version specified
# "requests", # ❌ Could break unexpectedly
# ]
# ///
```
**CORRECT**:
```python
# /// script
# dependencies = [
# "httpx>=0.27.0", # ✓ Minimum version specified
# "requests>=2.31.0", # ✓ Prevents breaking changes
# ]
# ///
```
### ❌ Overly Strict Pinning
**WRONG** (for utility scripts):
```python
# /// script
# dependencies = [
# "httpx==0.27.0", # ❌ Too strict, prevents updates
# "rich==13.7.0", # ❌ Blocks security fixes
# ]
# ///
```
**CORRECT**:
```python
# /// script
# dependencies = [
# "httpx>=0.27.0", # ✓ Allows updates
# "rich>=13.0.0", # ✓ Allows security fixes
# ]
# ///
```
**NOTE**: Exact pinning (`==`) is appropriate for deployment scripts where reproducibility is critical.
## Additional Pitfalls
### ❌ Missing Shebang
**WRONG**:
```python
# No shebang - script won't be directly executable
# /// script
# dependencies = ["requests"]
# ///
```
**CORRECT**:
```python
#!/usr/bin/env -S uv run --script
# /// script
# dependencies = ["requests"]
# ///
```
### ❌ Broad Exception Handling
**WRONG**:
```python
try:
do_something()
except Exception: # Too broad!
pass
```
**CORRECT**:
```python
try:
do_something()
except (FileNotFoundError, PermissionError) as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
```
### ❌ Platform-Specific Code Without Guards
**WRONG**:
```python
import pwd # Unix-only, crashes on Windows
user = pwd.getpwuid(os.getuid())
```
**CORRECT**:
```python
import sys
if sys.platform != "win32":
import pwd
user = pwd.getpwuid(os.getuid())
else:
user = os.environ.get("USERNAME")
```
## Summary
**Never use**:
- `[tool.uv.metadata]` (invalid field)
- Custom fields in PEP 723 metadata (only `requires-python` and `dependencies`)
- Hardcoded secrets
- Scripts for complex applications (>500 lines, web apps, services)
**Always use**:
- Valid PEP 723 format only
- `[tool.uv]` (without `.metadata`) for valid fields like `exclude-newer`
- Environment variables or Infisical for secrets
- Error handling for external calls
- Version constraints on dependencies
- Proper projects when scripts become too complex

View File

@@ -0,0 +1,363 @@
# When NOT to Use Single-File Scripts
This document helps determine when to use a single-file uv script vs. when to use a proper uv project.
## Decision Tree
```text
Is this a Python program?
├─ No → Use appropriate language/tool
└─ Yes
├─ Is it a one-time task or simple automation?
│ ├─ Yes → Consider single-file script
│ └─ No → Use proper uv project
└─ Does it meet ANY of these criteria?
├─ >500 lines of code → Use proper uv project
├─ Multiple Python files needed → Use proper uv project
├─ Web application or API → Use proper uv project
├─ Long-running service → Use proper uv project
├─ Complex configuration → Use proper uv project
├─ Shared library code → Use proper uv project
├─ Heavy ML/data dependencies → Use proper uv project
└─ None of the above → Single-file script is appropriate
```
## Use Proper uv Project When
### 1. Code Complexity
**Use project if**:
- Script exceeds 500 lines
- Logic is spread across multiple functions/classes
- Code would benefit from splitting into modules
- Complex data models or class hierarchies
**Example - Too Complex for Script**:
```python
# This needs a proper project structure:
# - 800 lines of code
# - Multiple classes (User, Database, API, Config)
# - Would be clearer as separate modules
# - Needs tests
```
### 2. Multiple Files Needed
**Use project if**:
- Shared utilities across multiple scripts
- Common data models used by different tools
- Reusable library code
- Multiple entry points
**Example**:
```text
# This needs a project:
my-tool/
├── src/
│ ├── __init__.py
│ ├── database.py # Shared by multiple tools
│ ├── models.py # Common data structures
│ └── utils.py # Utility functions
├── scripts/
│ ├── import_data.py # Uses shared code
│ └── export_data.py # Uses shared code
└── pyproject.toml
```
### 3. Web Applications
**Use project for**:
- Flask/FastAPI/Django applications
- REST APIs
- Web services
- Applications with routes/controllers
**Example - Needs Project**:
```python
# Don't use single-file script for web apps:
from flask import Flask, request, jsonify
app = Flask(__name__)
# 50+ routes
# Database models
# Authentication
# Background tasks
# Configuration management
# This should be a proper project structure
```
### 4. Long-Running Services
**Use project for**:
- Daemons
- Background workers
- Queue consumers
- Services that run continuously
**Example**:
```python
# Don't use script for services:
# - Runs 24/7
# - Monitors message queue
# - Complex retry logic
# - Logging configuration
# - Health checks
# - Graceful shutdown
# Needs proper project structure with:
# - Proper logging setup
# - Configuration management
# - Process management (systemd/supervisor)
```
### 5. Complex Configuration
**Use project if**:
- Multiple environment configs (dev/staging/prod)
- YAML/JSON configuration files
- Feature flags
- Database connection pools
**Example**:
```text
# This needs a project:
config/
├── dev.yaml
├── staging.yaml
└── production.yaml
# Single-file scripts should use simple env vars instead
```
### 6. Heavy Dependencies
**Use project for**:
- Machine learning frameworks (TensorFlow, PyTorch)
- Large data processing (PySpark)
- Complex scientific computing
- GUI frameworks
**Example - Too Heavy**:
```python
# /// script
# dependencies = [
# "tensorflow>=2.15.0", # ❌ ~500MB download
# "torch>=2.1.0", # ❌ ~800MB download
# "transformers>=4.35.0", # ❌ Complex dependency tree
# ]
# ///
# Use proper project with managed virtual environment
```
### 7. Testing Requirements
**Use project if**:
- Comprehensive test suite needed
- Multiple test files
- Fixtures and mocking
- CI/CD integration
**Example**:
```text
# This needs a project:
tests/
├── unit/
│ ├── test_models.py
│ ├── test_utils.py
│ └── test_api.py
├── integration/
│ └── test_database.py
└── conftest.py
# Can't reasonably organize this with single-file script
```
### 8. Team Collaboration
**Use project if**:
- Multiple developers working on code
- Code review processes
- Versioning and releases
- Documentation requirements
## Single-File Scripts ARE Appropriate For
### ✅ Good Use Cases
**One-time tasks**:
```python
# Convert CSV format
# Migrate data between systems
# Clean up old files
# Generate reports
```
**Simple automation**:
```python
# Check server health
# Send notifications
# Backup files
# Parse logs
```
**CLI utilities**:
```python
# Format files
# Validate data
# Query APIs
# Process input
```
**Prototyping**:
```python
# Test API endpoints
# Experiment with libraries
# Quick data analysis
# Proof of concept
```
### ✅ Characteristics of Good Single-File Scripts
- **<500 lines of code**
- **Self-contained logic**
- **Simple, clear purpose**
- **Minimal dependencies (1-5 packages)**
- **Standalone execution**
- **Quick to understand**
## Examples of Good Single-File Scripts
### Example 1: Health Check
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "psutil>=5.9.0",
# "rich>=13.0.0",
# ]
# ///
"""Check system health and display metrics."""
import psutil
from rich import print
def main():
cpu = psutil.cpu_percent()
mem = psutil.virtual_memory().percent
disk = psutil.disk_usage('/').percent
print(f"CPU: {cpu}% | Memory: {mem}% | Disk: {disk}%")
if cpu > 80 or mem > 80 or disk > 80:
print("[red]⚠ High resource usage![/red]")
exit(1)
if __name__ == "__main__":
main()
```
### Example 2: API Query
```python
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx>=0.27.0",
# ]
# ///
"""Query API and display results."""
import httpx
import sys
def main():
response = httpx.get("https://api.github.com/users/octocat")
response.raise_for_status()
data = response.json()
print(f"Name: {data['name']}")
print(f"Public repos: {data['public_repos']}")
if __name__ == "__main__":
main()
```
## Migration Path
**When a script outgrows single-file format**:
1. Create proper uv project:
```bash
uv init my-tool
cd my-tool
```
2. Move script logic to `src/`:
```bash
mv script.py src/my_tool/main.py
```
3. Add dependencies to `pyproject.toml`:
```toml
[project]
dependencies = [
"httpx>=0.27.0",
"rich>=13.0.0",
]
```
4. Create entry point in `pyproject.toml`:
```toml
[project.scripts]
my-tool = "my_tool.main:main"
```
## Summary
**Use single-file scripts for**:
- Simple automation (<500 lines)
- One-off tasks
- CLI utilities
- Prototypes
- Standalone tools
**Use proper uv projects for**:
- Complex applications (>500 lines)
- Multiple files/modules
- Web applications
- Long-running services
- Heavy dependencies
- Team collaboration
- Comprehensive testing
**When in doubt**: Start with a script. If it grows too complex, migrate to a project.