Files
StarPunk/docs/decisions/ADR-006-python-virtual-environment-uv.md
2025-11-18 19:21:31 -07:00

16 KiB

ADR-006: Python Virtual Environment Management with uv

Status

Accepted

Context

StarPunk is a Python-based web application that requires dependency management and virtual environment isolation. Developer agents (AI assistants like Claude Code) need clear, unambiguous standards for:

  • Creating and managing Python virtual environments
  • Installing and tracking dependencies
  • Ensuring reproducible development environments
  • Avoiding common pitfalls (polluting global Python, dependency conflicts)
  • Maintaining consistency across development and deployment

Traditional tools (pip, venv, virtualenv, poetry, pipenv) have various limitations:

  • pip + venv: Slow dependency resolution, manual requirements.txt management
  • poetry: Complex configuration, slow, dependency lock issues
  • pipenv: Abandoned maintenance, slow performance
  • conda: Heavyweight, non-standard for web development

We need a tool that is fast, simple, and provides excellent developer experience while maintaining compatibility with standard Python packaging.

Decision

Use uv for all Python virtual environment and dependency management in StarPunk.

uv will be the standard tool for:

  • Creating virtual environments
  • Installing dependencies
  • Managing requirements
  • Running Python commands in the virtual environment
  • Synchronizing dependencies

Rationale

Simplicity Score: 10/10

  • Single tool for all environment management
  • Simple command syntax (uv venv, uv pip install, uv run)
  • Drop-in replacement for pip and virtualenv
  • No complex configuration files
  • Works with standard requirements.txt
  • Written in Rust, installed as single binary

Performance Score: 10/10

  • 10-100x faster than pip for dependency resolution
  • Parallel downloads and installations
  • Efficient caching mechanism
  • Near-instant virtual environment creation
  • Minimal overhead for running commands

Fitness Score: 9/10

  • Perfect for small to medium Python projects
  • Excellent for single-developer projects
  • Works with standard Python packaging (PEP 517/518)
  • Compatible with requirements.txt workflow
  • Supports editable installs for development
  • Works seamlessly with Flask and all our dependencies

Maintenance Score: 9/10

  • Actively developed by Astral (creators of ruff)
  • Strong community adoption
  • Excellent documentation
  • Regular updates and improvements
  • Modern codebase (Rust)
  • Backed by funding and commercial support

Standards Compliance: Pass

  • Full compatibility with pip
  • Works with PyPI and all standard package indices
  • Supports PEP 440 version specifiers
  • Compatible with requirements.txt format
  • Works with standard Python virtual environments
  • No proprietary lock files (uses standard formats)

Implementation Details

1. Installation Standards

System-Level uv Installation

Developer agents MUST ensure uv is installed before creating environments:

# Check if uv is installed
which uv

# If not installed, install via pip (fallback)
pip install uv

# Or install via official installer (preferred on Linux/macOS)
curl -LsSf https://astral.sh/uv/install.sh | sh

Verification

# Verify uv installation
uv --version
# Expected output: uv 0.x.x (or newer)

2. Virtual Environment Creation Standards

Location and Naming

  • Standard location: /home/phil/Projects/starpunk/.venv
  • Name: Always use .venv (hidden directory)
  • DO NOT use: venv, env, virtualenv, or custom names

Creation Command

# Create virtual environment with uv
cd /home/phil/Projects/starpunk
uv venv .venv

# Specify Python version (recommended)
uv venv .venv --python 3.11

Post-Creation Verification

# Verify .venv directory exists
ls -la /home/phil/Projects/starpunk/.venv

# Verify Python executable
/home/phil/Projects/starpunk/.venv/bin/python --version

3. Dependency Installation Standards

Using requirements.txt (Primary Method)

# Install all dependencies from requirements.txt
uv pip install -r /home/phil/Projects/starpunk/requirements.txt

# Verify installation
uv pip list

Installing Individual Packages

# Install a single package
uv pip install flask==3.0.*

# Install multiple packages
uv pip install flask markdown feedgen

Development Dependencies

# Install dev dependencies (if requirements-dev.txt exists)
uv pip install -r /home/phil/Projects/starpunk/requirements-dev.txt

4. Running Commands in Virtual Environment

# Run Python script
uv run /home/phil/Projects/starpunk/.venv/bin/python script.py

# Run Flask development server
uv run /home/phil/Projects/starpunk/.venv/bin/flask run

# Run pytest
uv run /home/phil/Projects/starpunk/.venv/bin/pytest

# Run Python REPL
uv run /home/phil/Projects/starpunk/.venv/bin/python

Direct Execution (Alternative)

# Execute using absolute path to venv Python
/home/phil/Projects/starpunk/.venv/bin/python script.py
/home/phil/Projects/starpunk/.venv/bin/flask run
/home/phil/Projects/starpunk/.venv/bin/pytest

5. Dependency Tracking Standards

Generating requirements.txt

# Freeze current environment to requirements.txt
uv pip freeze > /home/phil/Projects/starpunk/requirements.txt

# Freeze with sorted output for consistency
uv pip freeze | sort > /home/phil/Projects/starpunk/requirements.txt

Adding New Dependencies

When adding a new dependency:

  1. Install the package: uv pip install package-name
  2. Update requirements.txt: uv pip freeze | sort > requirements.txt
  3. Verify installation: uv pip list | grep package-name

6. Environment Updates and Maintenance

Updating Dependencies

# Update a specific package
uv pip install --upgrade flask

# Update all packages (use with caution)
uv pip install --upgrade -r requirements.txt

# Regenerate requirements.txt after updates
uv pip freeze | sort > requirements.txt

Cleaning and Rebuilding

# Remove virtual environment
rm -rf /home/phil/Projects/starpunk/.venv

# Recreate from scratch
uv venv .venv --python 3.11
uv pip install -r requirements.txt

Developer Agent Standards

Critical Rules for AI Assistants

Rule 1: ALWAYS Check for Existing Virtual Environment

Before creating a new virtual environment, ALWAYS check:

# Check if .venv exists
if [ -d "/home/phil/Projects/starpunk/.venv" ]; then
  echo "Virtual environment exists"
  /home/phil/Projects/starpunk/.venv/bin/python --version
else
  echo "Virtual environment does not exist"
fi

NEVER create a new virtual environment if one already exists without explicit user permission.

Rule 2: ALWAYS Use Absolute Paths

Agent threads reset cwd between bash calls. ALWAYS use absolute paths:

CORRECT:

uv venv /home/phil/Projects/starpunk/.venv
/home/phil/Projects/starpunk/.venv/bin/python script.py
uv pip install -r /home/phil/Projects/starpunk/requirements.txt

INCORRECT:

uv venv .venv  # Relative path - WRONG
./venv/bin/python script.py  # Relative path - WRONG
uv pip install -r requirements.txt  # Relative path - WRONG

Rule 3: Verify Before Executing

Before running Python commands, verify the virtual environment:

# Verification checklist
[ -d "/home/phil/Projects/starpunk/.venv" ] && echo "✓ venv exists" || echo "✗ venv missing"
[ -f "/home/phil/Projects/starpunk/.venv/bin/python" ] && echo "✓ Python exists" || echo "✗ Python missing"
/home/phil/Projects/starpunk/.venv/bin/python --version

Rule 4: Handle Errors Gracefully

If virtual environment operations fail:

  1. Check uv installation: which uv
  2. Check Python version: python3 --version
  3. Check disk space: df -h /home/phil/Projects/starpunk
  4. Report specific error to user with context
  5. DO NOT silently continue with global Python

Rule 5: Never Modify Global Python

NEVER run these commands:

# FORBIDDEN - modifies global Python
pip install package
python3 -m pip install package
sudo pip install package

ALWAYS use virtual environment:

# CORRECT - uses virtual environment
uv pip install package
/home/phil/Projects/starpunk/.venv/bin/pip install package

Rule 6: Track Dependency Changes

After installing or removing packages:

  1. Update requirements.txt: uv pip freeze | sort > requirements.txt
  2. Verify changes: git diff requirements.txt (if applicable)
  3. Inform user of changes made

Standard Agent Workflow

Scenario 1: First-Time Setup

# 1. Check if venv exists
if [ ! -d "/home/phil/Projects/starpunk/.venv" ]; then
  echo "Creating virtual environment..."
  uv venv /home/phil/Projects/starpunk/.venv --python 3.11
fi

# 2. Verify creation
/home/phil/Projects/starpunk/.venv/bin/python --version

# 3. Install dependencies (if requirements.txt exists)
if [ -f "/home/phil/Projects/starpunk/requirements.txt" ]; then
  uv pip install -r /home/phil/Projects/starpunk/requirements.txt
fi

# 4. Verify installation
uv pip list

Scenario 2: Running Development Server

# 1. Verify venv exists
[ -d "/home/phil/Projects/starpunk/.venv" ] || echo "ERROR: Virtual environment missing"

# 2. Verify Flask is installed
/home/phil/Projects/starpunk/.venv/bin/python -c "import flask; print(flask.__version__)"

# 3. Run Flask development server
/home/phil/Projects/starpunk/.venv/bin/flask --app /home/phil/Projects/starpunk/app.py run

Scenario 3: Adding New Dependency

# 1. Install package
uv pip install httpx

# 2. Verify installation
uv pip show httpx

# 3. Update requirements.txt
uv pip freeze | sort > /home/phil/Projects/starpunk/requirements.txt

# 4. Confirm to user
echo "Added httpx to project dependencies"

Scenario 4: Running Tests

# 1. Verify pytest is installed
/home/phil/Projects/starpunk/.venv/bin/python -c "import pytest; print(pytest.__version__)"

# 2. Run tests
/home/phil/Projects/starpunk/.venv/bin/pytest /home/phil/Projects/starpunk/tests/

# 3. Run tests with coverage (if pytest-cov installed)
/home/phil/Projects/starpunk/.venv/bin/pytest --cov=/home/phil/Projects/starpunk/src /home/phil/Projects/starpunk/tests/

Project-Specific Standards

Python Version Requirements

  • Minimum: Python 3.11
  • Recommended: Python 3.11 or 3.12
  • Rationale: Modern Python features, improved performance, security updates

Directory Structure

/home/phil/Projects/starpunk/
├── .venv/                 # Virtual environment (NEVER commit)
├── requirements.txt       # Production dependencies
├── requirements-dev.txt   # Development dependencies (optional)
├── src/                   # Application source code
├── tests/                 # Test files
└── docs/                  # Documentation

.gitignore Requirements

The following MUST be in .gitignore:

# Virtual Environment
.venv/
venv/
env/
ENV/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python

Environment Variables

Use python-dotenv for configuration:

# .env file (NEVER commit to git)
FLASK_APP=app.py
FLASK_ENV=development
SECRET_KEY=your-secret-key
DATABASE_PATH=/home/phil/Projects/starpunk/data/starpunk.db

Load in application:

from dotenv import load_dotenv
load_dotenv()

Requirements.txt Format

Follow these conventions:

# Requirements.txt - StarPunk Dependencies
# Generated: 2025-11-18

# Web Framework
flask==3.0.*

# Content Processing
markdown==3.5.*

# Feed Generation
feedgen==1.0.*

# HTTP Client
httpx==0.27.*

# Configuration
python-dotenv==1.0.*

Consequences

Positive

  • 10-100x faster dependency resolution and installation
  • Consistent environments across development and deployment
  • Simple workflow - one tool for all Python environment tasks
  • No activation required - uv run handles environment automatically
  • Excellent caching - faster subsequent installations
  • Standard compatibility - works with all existing Python tools
  • Clear agent guidelines - reduces errors in automated workflows
  • Isolated dependencies - no conflicts with system Python

Negative

  • Additional tool dependency - requires uv installation
  • Less familiar - newer tool, smaller community than pip
  • Rust dependency - uv is written in Rust (but distributed as binary)

Mitigation

  • uv is easy to install (single binary, no compilation needed)
  • uv is pip-compatible (drop-in replacement)
  • Fallback to pip + venv is always possible
  • Documentation and agent standards make adoption easy
  • Active development and growing adoption reduce risk

Trade-offs Accepted

  • uv vs poetry: We chose simplicity over advanced features
  • uv vs pipenv: We chose active maintenance and speed
  • uv vs pip: We chose performance over ubiquity
  • Single tool complexity: Better than managing multiple tools

Verification Checklist

Before considering the environment correctly set up, verify:

  • uv is installed and accessible: which uv
  • Virtual environment exists: ls -la /home/phil/Projects/starpunk/.venv
  • Python version is 3.11+: /home/phil/Projects/starpunk/.venv/bin/python --version
  • Dependencies installed: uv pip list shows Flask, markdown, feedgen, httpx
  • requirements.txt exists and is up to date
  • .venv is in .gitignore
  • Flask runs: /home/phil/Projects/starpunk/.venv/bin/flask --version

Integration with Development Workflow

Running Flask Application

# Development server
/home/phil/Projects/starpunk/.venv/bin/flask --app app.py run --debug

# Production server (using gunicorn)
/home/phil/Projects/starpunk/.venv/bin/gunicorn app:app

Running Tests

# All tests
/home/phil/Projects/starpunk/.venv/bin/pytest

# Specific test file
/home/phil/Projects/starpunk/.venv/bin/pytest tests/test_api.py

# With coverage
/home/phil/Projects/starpunk/.venv/bin/pytest --cov=src tests/

Code Quality Tools

# Format code with black
/home/phil/Projects/starpunk/.venv/bin/black src/

# Lint with flake8
/home/phil/Projects/starpunk/.venv/bin/flake8 src/

# Type checking with mypy (if added)
/home/phil/Projects/starpunk/.venv/bin/mypy src/

Alternatives Considered

pip + venv (Rejected)

  • Simplicity: 8/10 - Standard Python tools, well-known
  • Performance: 4/10 - Very slow dependency resolution
  • Fitness: 7/10 - Works but painful for larger dependency trees
  • Maintenance: 10/10 - Built into Python, always maintained
  • Verdict: Too slow, poor developer experience, but acceptable fallback

poetry (Rejected)

  • Simplicity: 5/10 - Complex pyproject.toml, lock file management
  • Performance: 5/10 - Slow dependency resolution
  • Fitness: 6/10 - Overkill for simple project, lock files add complexity
  • Maintenance: 7/10 - Maintained but has had reliability issues
  • Verdict: Too complex for "minimal code" philosophy

pipenv (Rejected)

  • Simplicity: 6/10 - Simpler than poetry, but still adds abstraction
  • Performance: 4/10 - Known performance issues
  • Fitness: 5/10 - Previously recommended, now effectively abandoned
  • Maintenance: 2/10 - Minimal maintenance, community has moved on
  • Verdict: Dead project, poor performance

conda (Rejected)

  • Simplicity: 3/10 - Heavy, complex environment management
  • Performance: 5/10 - Slower than uv, larger downloads
  • Fitness: 2/10 - Designed for data science, not web development
  • Maintenance: 9/10 - Well maintained, large ecosystem
  • Verdict: Wrong tool for web application development

PDM (Considered)

  • Simplicity: 7/10 - Modern, PEP 582 support
  • Performance: 8/10 - Fast, but not as fast as uv
  • Fitness: 7/10 - Good for modern Python projects
  • Maintenance: 8/10 - Actively maintained, growing community
  • Verdict: Good alternative, but uv is faster and simpler

References

Change Log

  • 2025-11-18: Initial version - Established uv as standard tool for StarPunk Python environment management