Switch backend to uv package manager, update dependencies, and refactor Dockerfile for modern Python tooling
- Migrated dependency management to `uv` for faster, reproducible builds and added `uv.lock`. - Updated `Dockerfile`: replaced pip with `uv`, added `uv` installation, and refined dependency installation for development and production. - Enhanced `pyproject.toml`: reorganized dependencies, added support for `uv`. - Updated docs and Makefile with `uv` usage instructions for streamlined setup and testing.
This commit is contained in:
77
CLAUDE.md
77
CLAUDE.md
@@ -62,13 +62,28 @@ frontend/src/
|
|||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
#### Setup
|
#### Setup
|
||||||
|
|
||||||
|
**Dependencies are managed with [uv](https://docs.astral.sh/uv/) - the modern, fast Python package manager.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
python -m venv .venv
|
|
||||||
source .venv/bin/activate # or .venv\Scripts\activate on Windows
|
# Install uv (if not already installed)
|
||||||
pip install -r requirements.txt
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
|
||||||
|
# Install all dependencies (production + dev) from uv.lock
|
||||||
|
uv sync --extra dev
|
||||||
|
|
||||||
|
# Or use the Makefile
|
||||||
|
make install-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Why uv?**
|
||||||
|
- 🚀 10-100x faster than pip
|
||||||
|
- 🔒 Reproducible builds with `uv.lock`
|
||||||
|
- 📦 Modern dependency resolution
|
||||||
|
- ⚡ Built by Astral (creators of Ruff)
|
||||||
|
|
||||||
#### Database Migrations
|
#### Database Migrations
|
||||||
```bash
|
```bash
|
||||||
# Using the migration helper (preferred)
|
# Using the migration helper (preferred)
|
||||||
@@ -93,27 +108,34 @@ alembic upgrade head
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run all tests (uses pytest-xdist for parallel execution)
|
# Run all tests (uses pytest-xdist for parallel execution)
|
||||||
IS_TEST=True pytest
|
make test
|
||||||
|
|
||||||
# Run with coverage (use -n 0 for accurate coverage)
|
# Run with coverage report
|
||||||
IS_TEST=True pytest --cov=app --cov-report=term-missing -n 0
|
make test-cov
|
||||||
|
|
||||||
|
# Or run directly with uv
|
||||||
|
IS_TEST=True uv run pytest
|
||||||
|
|
||||||
# Run specific test file
|
# Run specific test file
|
||||||
IS_TEST=True pytest tests/api/test_auth.py -v
|
IS_TEST=True uv run pytest tests/api/test_auth.py -v
|
||||||
|
|
||||||
# Run single test
|
# Run single test
|
||||||
IS_TEST=True pytest tests/api/test_auth.py::TestLogin::test_login_success -v
|
IS_TEST=True uv run pytest tests/api/test_auth.py::TestLogin::test_login_success -v
|
||||||
|
```
|
||||||
|
|
||||||
# Run with HTML coverage report
|
**Available Make Commands:**
|
||||||
IS_TEST=True pytest --cov=app --cov-report=html -n 0
|
```bash
|
||||||
open htmlcov/index.html
|
make help # Show all available commands
|
||||||
|
make install-dev # Install all dependencies
|
||||||
|
make validate # Run lint + format + type checks
|
||||||
|
make test # Run tests
|
||||||
|
make test-cov # Run tests with coverage
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Running Locally
|
#### Running Locally
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
source .venv/bin/activate
|
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
@@ -467,6 +489,35 @@ Automatically applied via middleware in `main.py`:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Development Tooling Stack
|
||||||
|
|
||||||
|
**State-of-the-art Python tooling (Nov 2025):**
|
||||||
|
|
||||||
|
### Dependency Management: uv
|
||||||
|
- **Fast**: 10-100x faster than pip
|
||||||
|
- **Reliable**: Reproducible builds with `uv.lock` lockfile
|
||||||
|
- **Modern**: Built by Astral (Ruff creators) in Rust
|
||||||
|
- **Commands**:
|
||||||
|
- `make install-dev` - Install all dependencies
|
||||||
|
- `make sync` - Sync from lockfile
|
||||||
|
- `uv add <package>` - Add new dependency
|
||||||
|
- `uv add --dev <package>` - Add dev dependency
|
||||||
|
|
||||||
|
### Code Quality: Ruff + mypy
|
||||||
|
- **Ruff**: All-in-one linting, formatting, and import sorting
|
||||||
|
- Replaces: Black, Flake8, isort
|
||||||
|
- **10-100x faster** than alternatives
|
||||||
|
- `make lint`, `make format`, `make validate`
|
||||||
|
- **mypy**: Type checking with Pydantic plugin
|
||||||
|
- Gradual typing approach
|
||||||
|
- Strategic per-module configurations
|
||||||
|
|
||||||
|
### Configuration: pyproject.toml
|
||||||
|
- Single source of truth for all tools
|
||||||
|
- Dependencies defined in `[project.dependencies]`
|
||||||
|
- Dev dependencies in `[project.optional-dependencies]`
|
||||||
|
- Tool configs: Ruff, mypy, pytest, coverage
|
||||||
|
|
||||||
## Current Project Status (Nov 2025)
|
## Current Project Status (Nov 2025)
|
||||||
|
|
||||||
### Completed Features
|
### Completed Features
|
||||||
|
|||||||
@@ -7,16 +7,27 @@ RUN groupadd -r appuser && useradd -r -g appuser appuser
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
PYTHONPATH=/app
|
PYTHONPATH=/app \
|
||||||
|
UV_COMPILE_BYTECODE=1 \
|
||||||
|
UV_LINK_MODE=copy
|
||||||
|
|
||||||
|
# Install system dependencies and uv
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends gcc postgresql-client curl && \
|
apt-get install -y --no-install-recommends gcc postgresql-client curl ca-certificates && \
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt .
|
# Add uv to PATH
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
ENV PATH="/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
|
||||||
|
# Install dependencies using uv (development mode with dev dependencies)
|
||||||
|
RUN uv sync --extra dev --frozen
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY entrypoint.sh /usr/local/bin/
|
COPY entrypoint.sh /usr/local/bin/
|
||||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
@@ -38,16 +49,27 @@ RUN groupadd -r appuser && useradd -r -g appuser appuser
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
PYTHONPATH=/app
|
PYTHONPATH=/app \
|
||||||
|
UV_COMPILE_BYTECODE=1 \
|
||||||
|
UV_LINK_MODE=copy
|
||||||
|
|
||||||
|
# Install system dependencies and uv
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends postgresql-client curl && \
|
apt-get install -y --no-install-recommends postgresql-client curl ca-certificates && \
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt .
|
# Add uv to PATH
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
ENV PATH="/root/.cargo/bin:$PATH"
|
||||||
|
|
||||||
|
# Copy dependency files
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
|
||||||
|
# Install only production dependencies using uv (no dev dependencies)
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY entrypoint.sh /usr/local/bin/
|
COPY entrypoint.sh /usr/local/bin/
|
||||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||||
@@ -63,4 +85,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
|||||||
CMD curl -f http://localhost:8000/health || exit 1
|
CMD curl -f http://localhost:8000/health || exit 1
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
.PHONY: help lint lint-fix format format-check type-check test test-cov validate clean install-dev
|
.PHONY: help lint lint-fix format format-check type-check test test-cov validate clean install-dev sync
|
||||||
|
|
||||||
# Virtual environment binaries
|
|
||||||
VENV_BIN = .venv/bin
|
|
||||||
PYTHON = $(VENV_BIN)/python
|
|
||||||
PIP = $(VENV_BIN)/pip
|
|
||||||
PYTEST = $(VENV_BIN)/pytest
|
|
||||||
RUFF = $(VENV_BIN)/ruff
|
|
||||||
MYPY = $(VENV_BIN)/mypy
|
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
help:
|
help:
|
||||||
@echo "🚀 FastAPI Backend - Development Commands"
|
@echo "🚀 FastAPI Backend - Development Commands"
|
||||||
@echo ""
|
@echo ""
|
||||||
|
@echo "Setup:"
|
||||||
|
@echo " make install-dev - Install all dependencies with uv (includes dev)"
|
||||||
|
@echo " make sync - Sync dependencies from uv.lock"
|
||||||
|
@echo ""
|
||||||
@echo "Quality Checks:"
|
@echo "Quality Checks:"
|
||||||
@echo " make lint - Run Ruff linter (check only)"
|
@echo " make lint - Run Ruff linter (check only)"
|
||||||
@echo " make lint-fix - Run Ruff linter with auto-fix"
|
@echo " make lint-fix - Run Ruff linter with auto-fix"
|
||||||
@@ -24,33 +20,46 @@ help:
|
|||||||
@echo " make test - Run pytest"
|
@echo " make test - Run pytest"
|
||||||
@echo " make test-cov - Run pytest with coverage report"
|
@echo " make test-cov - Run pytest with coverage report"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Setup:"
|
@echo "Cleanup:"
|
||||||
@echo " make install-dev - Install all development dependencies"
|
|
||||||
@echo " make clean - Remove cache and build artifacts"
|
@echo " make clean - Remove cache and build artifacts"
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Setup & Cleanup
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
install-dev:
|
||||||
|
@echo "📦 Installing all dependencies with uv (includes dev)..."
|
||||||
|
@uv sync --extra dev
|
||||||
|
@echo "✅ Development environment ready!"
|
||||||
|
|
||||||
|
sync:
|
||||||
|
@echo "🔄 Syncing dependencies from uv.lock..."
|
||||||
|
@uv sync --extra dev
|
||||||
|
@echo "✅ Dependencies synced!"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Code Quality
|
# Code Quality
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
@echo "🔍 Running Ruff linter..."
|
@echo "🔍 Running Ruff linter..."
|
||||||
@$(RUFF) check app/ tests/
|
@uv run ruff check app/ tests/
|
||||||
|
|
||||||
lint-fix:
|
lint-fix:
|
||||||
@echo "🔧 Running Ruff linter with auto-fix..."
|
@echo "🔧 Running Ruff linter with auto-fix..."
|
||||||
@$(RUFF) check --fix app/ tests/
|
@uv run ruff check --fix app/ tests/
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@echo "✨ Formatting code with Ruff..."
|
@echo "✨ Formatting code with Ruff..."
|
||||||
@$(RUFF) format app/ tests/
|
@uv run ruff format app/ tests/
|
||||||
|
|
||||||
format-check:
|
format-check:
|
||||||
@echo "📋 Checking code formatting..."
|
@echo "📋 Checking code formatting..."
|
||||||
@$(RUFF) format --check app/ tests/
|
@uv run ruff format --check app/ tests/
|
||||||
|
|
||||||
type-check:
|
type-check:
|
||||||
@echo "🔎 Running mypy type checking..."
|
@echo "🔎 Running mypy type checking..."
|
||||||
@$(MYPY) app/
|
@uv run mypy app/
|
||||||
|
|
||||||
validate: lint format-check type-check
|
validate: lint format-check type-check
|
||||||
@echo "✅ All quality checks passed!"
|
@echo "✅ All quality checks passed!"
|
||||||
@@ -61,22 +70,17 @@ validate: lint format-check type-check
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
@echo "🧪 Running tests..."
|
@echo "🧪 Running tests..."
|
||||||
@IS_TEST=True PYTHONPATH=. $(PYTEST)
|
@IS_TEST=True PYTHONPATH=. uv run pytest
|
||||||
|
|
||||||
test-cov:
|
test-cov:
|
||||||
@echo "🧪 Running tests with coverage..."
|
@echo "🧪 Running tests with coverage..."
|
||||||
@IS_TEST=True PYTHONPATH=. $(PYTEST) --cov=app --cov-report=term-missing --cov-report=html -n 16
|
@IS_TEST=True PYTHONPATH=. uv run pytest --cov=app --cov-report=term-missing --cov-report=html -n 16
|
||||||
@echo "📊 Coverage report generated in htmlcov/index.html"
|
@echo "📊 Coverage report generated in htmlcov/index.html"
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Setup & Cleanup
|
# Cleanup
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
install-dev:
|
|
||||||
@echo "📦 Installing development dependencies..."
|
|
||||||
@$(PIP) install -r requirements.txt
|
|
||||||
@echo "✅ Development environment ready!"
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@echo "🧹 Cleaning up..."
|
@echo "🧹 Cleaning up..."
|
||||||
@find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
@find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
|
||||||
@@ -85,6 +89,8 @@ clean:
|
|||||||
@find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
|
@find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
|
||||||
@find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
|
@find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
|
||||||
@find . -type d -name "htmlcov" -exec rm -rf {} + 2>/dev/null || true
|
@find . -type d -name "htmlcov" -exec rm -rf {} + 2>/dev/null || true
|
||||||
|
@find . -type d -name "build" -exec rm -rf {} + 2>/dev/null || true
|
||||||
|
@find . -type d -name ".uv_cache" -exec rm -rf {} + 2>/dev/null || true
|
||||||
@find . -type f -name ".coverage" -delete 2>/dev/null || true
|
@find . -type f -name ".coverage" -delete 2>/dev/null || true
|
||||||
@find . -type f -name "*.pyc" -delete 2>/dev/null || true
|
@find . -type f -name "*.pyc" -delete 2>/dev/null || true
|
||||||
@echo "✅ Cleanup complete!"
|
@echo "✅ Cleanup complete!"
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
requires = ["setuptools>=61.0"]
|
requires = ["setuptools>=61.0"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
include = ["app*"]
|
||||||
|
exclude = ["tests*", "uploads*", "docs*"]
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "fast-next-backend"
|
name = "fast-next-backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -9,6 +13,65 @@ description = "FastAPI backend for Fast-Next template"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
# Core dependencies
|
||||||
|
dependencies = [
|
||||||
|
# Core FastAPI framework and dependencies
|
||||||
|
"fastapi>=0.115.8",
|
||||||
|
"uvicorn>=0.34.0",
|
||||||
|
"pydantic>=2.10.6",
|
||||||
|
"pydantic-settings>=2.2.1",
|
||||||
|
"python-multipart>=0.0.19",
|
||||||
|
"fastapi-utils==0.8.0",
|
||||||
|
|
||||||
|
# Database
|
||||||
|
"sqlalchemy>=2.0.29",
|
||||||
|
"alembic>=1.14.1",
|
||||||
|
"psycopg2-binary>=2.9.9",
|
||||||
|
"asyncpg>=0.29.0",
|
||||||
|
"aiosqlite==0.21.0",
|
||||||
|
|
||||||
|
# Environment configuration
|
||||||
|
"python-dotenv>=1.0.1",
|
||||||
|
|
||||||
|
# API utilities
|
||||||
|
"email-validator>=2.1.0.post1",
|
||||||
|
"ujson>=5.9.0",
|
||||||
|
|
||||||
|
# CORS and security
|
||||||
|
"starlette>=0.40.0",
|
||||||
|
"starlette-csrf>=1.4.5",
|
||||||
|
"slowapi>=0.1.9",
|
||||||
|
|
||||||
|
# Utilities
|
||||||
|
"httpx>=0.27.0",
|
||||||
|
"tenacity>=8.2.3",
|
||||||
|
"pytz>=2024.1",
|
||||||
|
"pillow>=10.3.0",
|
||||||
|
"apscheduler==3.11.0",
|
||||||
|
|
||||||
|
# Security and authentication (pinned for reproducibility)
|
||||||
|
"python-jose==3.4.0",
|
||||||
|
"passlib==1.7.4",
|
||||||
|
"bcrypt==4.2.1",
|
||||||
|
"cryptography==44.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Development dependencies
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
# Testing
|
||||||
|
"pytest>=8.0.0",
|
||||||
|
"pytest-asyncio>=0.23.5",
|
||||||
|
"pytest-cov>=4.1.0",
|
||||||
|
"pytest-xdist>=3.8.0",
|
||||||
|
"requests>=2.32.0",
|
||||||
|
"freezegun~=1.5.1",
|
||||||
|
|
||||||
|
# Development tools
|
||||||
|
"ruff>=0.8.0", # All-in-one: linting, formatting, import sorting
|
||||||
|
"mypy>=1.8.0", # Type checking
|
||||||
|
]
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Ruff Configuration - All-in-one linting, formatting, and import sorting
|
# Ruff Configuration - All-in-one linting, formatting, and import sorting
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
1521
backend/uv.lock
generated
Normal file
1521
backend/uv.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user