Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
__pycache__/
alembic/__pycache__/
*_cache
.git/
.gitignore/
.env
.venv
*.db
**/*.ipynb
assignments.md
13 changes: 4 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@ default_stages: [pre-push]
repos:
- repo: local
hooks:

- id: ruff
name: ruff (lint)
entry: uv run ruff check .
language: system
pass_filenames: false

- id: alembic-upgrade
name: alembic upgrade head
entry: sh -c 'DB_PATH="${DB_PATH:-test.db}" uv run alembic upgrade head'
entry: uv run ruff check
language: system
pass_filenames: false
types: [python]

- id: pytest
name: pytest
Expand All @@ -25,4 +20,4 @@ repos:
name: mypy
entry: uv run mypy app/
language: system
pass_filenames: false
pass_filenames: false
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
"python.testing.pytestEnabled": true,
"python.languageServer": "Jedi"
}
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM python:3.11-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

ENV DB_PATH="database.db"

WORKDIR /app

COPY pyproject.toml uv.lock ./
RUN uv sync --no-dev --frozen

COPY alembic.ini .
COPY alembic ./alembic
COPY app app/
COPY logs logs/

EXPOSE 8080

CMD ["uv", "run", "--no-dev", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]




31 changes: 24 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,42 @@ A FastAPI-based service that lets users upload, store, and download CSV files.
This project is built with:

- [FastAPI](https://fastapi.tiangolo.com/) – for the web API
- [Docker Compose](https://docs.docker.com/compose/) – for running the development environment
- [uv](https://github.com/astral-sh/uv) – for Python dependency and environment management
- [Alembic](https://alembic.sqlalchemy.org/) – for database migrations
- [Taskfile](https://taskfile.dev/) – to simplify common commands (like setup, running, and testing)

> ‼️ **You don’t need to worry about installing or configuring those manually** as Taskfile takes care of everything for you
> ‼️ **You don’t need to worry about installing or configuring those manually** as Docker and Taskfile take care of everything for you
> 👉 Follow the steps in [🚀 Getting Started](#getting-started)

## 🚀 Getting Started

- ✅ 1. Install Task (if you haven’t already). Installation guide → [https://taskfile.dev/installation](https://taskfile.dev/installation)
- ✅ 2. Run setup to install all dependencies and prepares database:
```bash
task setup
```
- ✅ Once the project is initialized, you can run the app with:
### 1. Install prerequisites

Make sure you have the following installed:

- [Docker](https://docs.docker.com/get-docker/)
- [Task](https://taskfile.dev/installation)

---

### 2. Start the development environment

Run:

```bash
task dev
```
This will:
- Build the Docker image
- Start the backend container
- Automatically run database migrations
- Start the FastAPI server

Once running, the API will be available at:
```
http://localhost:8000
```

### Pre-commit (Pre-push) Setup

Expand Down
25 changes: 8 additions & 17 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,35 @@
version: '3'
version: "3"

env:
DB_PATH: "database.db"

tasks:
check-uv:
silent: true
cmds:
- |
if ! command -v uv &> /dev/null; then
echo "🔧 Installing uv..."
curl -Ls https://astral.sh/uv/install.sh | sh
fi

setup:
desc: Initial project setup
deps: [check-uv, upgrade]
cmds:
- "docker compose build"

upgrade:
desc: Apply all migrations
cmds:
- uv run alembic upgrade head
- "docker compose exec backend uv run alembic upgrade head"

downgrade:
desc: Revert last migration
cmds:
- uv run alembic downgrade -1
- "docker compose exec backend uv run alembic downgrade -1"

migrate:
desc: 'Create a new Alembic migration (to use: task migrate -- "message")'
cmds:
- uv run alembic revision --autogenerate -m "{{.CLI_ARGS}}"
- "docker compose exec backend uv run alembic revision --autogenerate -m \"{{.CLI_ARGS}}\""

dev:
desc: Run FastAPI dev server
deps: [upgrade]
cmds:
- uv run uvicorn app.main:app --reload
- "docker compose up --build"

test:
desc: Run tests with separate DB
cmds:
- uv run pytest -vvs
- "docker compose exec backend sh -c 'DB_PATH=test.db uv run pytest -vvs'"
43 changes: 43 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
services:
database:
image: alpine:3.20
command: sh -c "echo database started"
volumes:
- sqlite_data:/db

backend:
build: .
environment:
DB_PATH: /db/database.db
ports:
- "8000:8000"
depends_on:
- database
volumes:
- sqlite_data:/db
command: >
sh -c "uv run alembic upgrade head &&
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload"

develop:
watch:
- path: ./app
action: sync
target: /app/app

- path: ./alembic
action: sync
target: /app/alembic

- path: ./alembic.ini
action: sync
target: /app/alembic.ini

- path: pyproject.toml
action: rebuild

- path: uv.lock
action: rebuild

volumes:
sqlite_data:
13 changes: 8 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ requires-python = ">=3.11"
dependencies = [
"alembic>=1.16.2",
"fastapi[standard]>=0.115.12",
"mypy>=1.15.0",
"pandas>=2.2.3",
"pandas-stubs>=2.2.3.250308",
"pyarrow>=22.0.0",
"pydantic-settings>=2.8.1",
"pytest-asyncio>=0.26.0",
"pytest-env>=1.1.5",
"sqlmodel>=0.0.24",
"uvicorn>=0.34.0",
]

[dependency-groups]
dev = [
"ipykernel>=6.29.5",
"mypy>=1.15.0",
"pandas-stubs>=2.2.3.250308",
"pre-commit>=4.5.0",
"pytest>=8.3.5",
"pytest-asyncio>=0.26.0",
"pytest-env>=1.1.5",
"ruff>=0.14.9",
]

Expand All @@ -34,4 +34,7 @@ env = [

[[tool.mypy.overrides]]
module = ["pyarrow", "pyarrow.csv", "pyarrow.parquet"]
ignore_missing_imports = true
ignore_missing_imports = true

[tool.ruff]
exclude = [".venv", "uv.lock"]
Loading
Loading