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:
2025-11-10 16:11:57 +01:00
parent 5c47be2ee5
commit 235c309e4e
5 changed files with 1709 additions and 46 deletions

View File

@@ -7,16 +7,27 @@ RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/app
PYTHONPATH=/app \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy
# Install system dependencies and uv
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 && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Add uv to PATH
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 entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
@@ -38,16 +49,27 @@ RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/app
PYTHONPATH=/app \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy
# Install system dependencies and uv
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 && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Add uv to PATH
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 entrypoint.sh /usr/local/bin/
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
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"]

View File

@@ -1,17 +1,13 @@
.PHONY: help lint lint-fix format format-check type-check test test-cov validate clean install-dev
# 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
.PHONY: help lint lint-fix format format-check type-check test test-cov validate clean install-dev sync
# Default target
help:
@echo "🚀 FastAPI Backend - Development Commands"
@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 " make lint - Run Ruff linter (check only)"
@echo " make lint-fix - Run Ruff linter with auto-fix"
@@ -24,33 +20,46 @@ help:
@echo " make test - Run pytest"
@echo " make test-cov - Run pytest with coverage report"
@echo ""
@echo "Setup:"
@echo " make install-dev - Install all development dependencies"
@echo "Cleanup:"
@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
# ============================================================================
lint:
@echo "🔍 Running Ruff linter..."
@$(RUFF) check app/ tests/
@uv run ruff check app/ tests/
lint-fix:
@echo "🔧 Running Ruff linter with auto-fix..."
@$(RUFF) check --fix app/ tests/
@uv run ruff check --fix app/ tests/
format:
@echo "✨ Formatting code with Ruff..."
@$(RUFF) format app/ tests/
@uv run ruff format app/ tests/
format-check:
@echo "📋 Checking code formatting..."
@$(RUFF) format --check app/ tests/
@uv run ruff format --check app/ tests/
type-check:
@echo "🔎 Running mypy type checking..."
@$(MYPY) app/
@uv run mypy app/
validate: lint format-check type-check
@echo "✅ All quality checks passed!"
@@ -61,22 +70,17 @@ validate: lint format-check type-check
test:
@echo "🧪 Running tests..."
@IS_TEST=True PYTHONPATH=. $(PYTEST)
@IS_TEST=True PYTHONPATH=. uv run pytest
test-cov:
@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"
# ============================================================================
# Setup & Cleanup
# Cleanup
# ============================================================================
install-dev:
@echo "📦 Installing development dependencies..."
@$(PIP) install -r requirements.txt
@echo "✅ Development environment ready!"
clean:
@echo "🧹 Cleaning up..."
@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 "*.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 "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 "*.pyc" -delete 2>/dev/null || true
@echo "✅ Cleanup complete!"

View File

@@ -2,6 +2,10 @@
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
include = ["app*"]
exclude = ["tests*", "uploads*", "docs*"]
[project]
name = "fast-next-backend"
version = "0.1.0"
@@ -9,6 +13,65 @@ description = "FastAPI backend for Fast-Next template"
readme = "README.md"
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
# ============================================================================

1521
backend/uv.lock generated Normal file

File diff suppressed because it is too large Load Diff