364 lines
7.1 KiB
Markdown
364 lines
7.1 KiB
Markdown
# 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.
|