Skip to content

Commit 2e41a7c

Browse files
Swap to using UV
1 parent 5056aa1 commit 2e41a7c

8 files changed

Lines changed: 2298 additions & 27 deletions

File tree

.github/copilot-instructions.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,12 @@ DEEPSEEK_API_KEY=...
6464
# Full stack with Docker Compose
6565
docker-compose up --build
6666

67-
# Backend only (for API development)
68-
cd backend && uvicorn fastapi_generate_quiz:app --reload --host 0.0.0.0 --port 8000
67+
# Backend only (for API development) - UV method
68+
cd backend && uv sync --dev --no-install-project && uv run --script dev
69+
70+
# Testing
71+
uv run pytest -v # Unit tests only (no API calls)
72+
uv run pytest -m integration # Integration tests with real API calls
6973

7074
# Access points:
7175
# - Frontend: http://localhost:8080
@@ -79,10 +83,11 @@ cd backend && uvicorn fastapi_generate_quiz:app --reload --host 0.0.0.0 --port 8
7983

8084
## Code Quality Standards
8185

82-
- **Linting**: Uses `ruff` for Python code formatting and linting
86+
- **Package Management**: Uses UV for fast dependency management and virtual environments
87+
- **Linting**: Uses `ruff` for Python code formatting and linting (`uv run ruff check .`)
8388
- **Type Checking**: Expected for new Python code
8489
- **Testing**: Always add unit tests; integration tests for API changes
85-
- **Dependencies**: Keep `requirements.txt` minimal; dev dependencies in `requirements-dev.txt`
90+
- **Dependencies**: Managed via `pyproject.toml`; dev dependencies in `[project.optional-dependencies]`
8691

8792
## Common Development Tasks
8893

.github/workflows/ci_python.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,23 @@ jobs:
2121
with:
2222
python-version: "3.10"
2323

24+
- name: Install UV
25+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
26+
2427
- name: Install dependencies
2528
run: |
26-
# Install ruff for linting and the development requirements (including pytest)
27-
pip install -r backend/requirements-dev.txt
29+
source $HOME/.cargo/env
30+
cd backend
31+
uv sync --dev --no-install-project
2832
2933
- name: Lint Python with ruff 🚀
30-
run: ruff check backend/
34+
run: |
35+
source $HOME/.cargo/env
36+
cd backend
37+
uv run ruff check .
3138
3239
- name: Run Pytest 🧪
33-
run: pytest -q backend/tests/ -v
40+
run: |
41+
source $HOME/.cargo/env
42+
cd backend
43+
uv run pytest -q tests/ -v

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,37 @@ This project uses Docker Compose to run both the FastAPI backend and the fronten
5454
### Running Locally
5555

5656
1. **Set Environment Variables**
57-
Make sure your `OPENAI_API_KEY` is set in your environment or in a `.env` file at the project root:
57+
Make sure your API keys are set in your environment or in a `.env` file at the project root:
5858
```sh
5959
export OPENAI_API_KEY=your_openai_api_key_here
60+
export GEMINI_API_KEY=your_gemini_api_key_here
61+
# ... other API keys
6062
```
6163
Or create a `.env` file with:
6264
```
6365
OPENAI_API_KEY=your_openai_api_key_here
66+
GEMINI_API_KEY=your_gemini_api_key_here
67+
# ... other API keys
6468
```
6569

66-
2. **Build and Run the Containers**
70+
2. **Build and Run with Docker Compose**
6771
From the project root, run:
6872
```sh
6973
docker-compose up --build
7074
```
7175
This command builds and starts both the backend and frontend containers.
7276

77+
3. **Alternative: Run Backend Locally with UV**
78+
For faster development iteration:
79+
```sh
80+
cd backend
81+
uv sync --dev
82+
uv run uvicorn fastapi_generate_quiz:app --reload --host 0.0.0.0 --port 8000
83+
```
84+
7385
3. **Access the Services**
7486
- **Backend API (FastAPI)**: [http://localhost:8000](http://localhost:8000)
7587
- **Frontend**: [http://localhost:8080](http://localhost:8080)
7688

77-
With these steps, you can easily test both the backend API and the static frontend locally using Docker Compose.
89+
With these steps, you can easily test both the backend API and the static frontend locally using Docker Compose or UV for faster backend development.
7890

backend/Dockerfile

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,23 @@
22
# https://fastapi.tiangolo.com/deployment/docker/#dockerfile
33
FROM python:3.10-slim
44

5+
# Install UV
6+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
7+
58
# Set working directory
69
WORKDIR /code
710

8-
# Copy requirements file and install dependencies
9-
COPY ./requirements.txt /code/requirements.txt
10-
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
11+
# Copy project files
12+
COPY ./pyproject.toml /code/pyproject.toml
13+
14+
# Install dependencies without installing the project itself
15+
RUN uv sync --no-dev --no-install-project
1116

1217
# Copy application code
1318
COPY . /code
1419

1520
# Command to run the application using Uvicorn
16-
CMD ["uvicorn", "fastapi_generate_quiz:app", "--host", "0.0.0.0", "--port", "8000"]
21+
CMD ["uv", "run", "uvicorn", "fastapi_generate_quiz:app", "--host", "0.0.0.0", "--port", "8000"]
1722

1823
# docker build -t fastapi_generate_quiz:latest . # Build container
1924
# docker run -p 8000:8000 -e OPENAI_API_KEY fastapi_generate_quiz:latest # Run container

backend/README.md

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,59 @@ Certain functions may require environment variables (e.g., `OPENAI_API_KEY`). Th
3434
## Debug
3535
To debug locally, follow these steps:
3636

37+
### Using UV (Recommended)
38+
39+
1. **Install UV** (if not already installed):
40+
```sh
41+
curl -LsSf https://astral.sh/uv/install.sh | sh
42+
```
43+
44+
2. **Install dependencies**:
45+
```sh
46+
cd backend
47+
uv sync --dev --no-install-project
48+
```
49+
50+
3. **Run the FastAPI application**:
51+
```sh
52+
# Option 1: Using the configured script
53+
uv run --script dev
54+
55+
# Option 2: Direct command
56+
uv run uvicorn fastapi_generate_quiz:app --reload --host 0.0.0.0 --port 8000
57+
```
58+
59+
4. **Test the endpoints** (requires valid API keys and quota):
60+
```sh
61+
# Test quiz generation (will fail if no API quota)
62+
curl "http://localhost:8000/GenerateQuiz?topic=UK%20History&difficulty=easy&n_questions=3"
63+
64+
# Test image generation
65+
curl "http://localhost:8000/GenerateImage?prompt=A%20Juicy%20Burger"
66+
```
67+
68+
5. **Run tests**:
69+
```sh
70+
# Unit tests only (default - no API calls required)
71+
uv run pytest -v
72+
73+
# Integration tests (requires API keys and quota)
74+
uv run pytest -m integration
75+
76+
# All tests
77+
uv run pytest -v --tb=short
78+
```
79+
80+
6. **Run linting**:
81+
```sh
82+
uv run ruff check .
83+
uv run ruff format .
84+
```
85+
86+
> **Note**: Direct execution of `generate_quiz.py` requires valid API keys and quota. For development without making API calls, use the unit tests (`uv run pytest -v`) which use mocked responses.
87+
88+
### Using Docker
89+
3790
1. **Build the Docker container**:
3891
```sh
3992
docker build -t fastapi_generate_quiz:latest .
@@ -56,6 +109,8 @@ To debug locally, follow these steps:
56109
curl "http://localhost:8000/GenerateImage?prompt=Kangeroo%20Playing%20BasketBall"
57110
```
58111

112+
### Docker Registry Commands
113+
59114
4. **Tag the Docker image for GitHub Container Registry**:
60115
```sh
61116
docker tag fastapi_generate_quiz:latest ghcr.io/djsaunders1997/fastapi_generate_quiz:latest
@@ -78,27 +133,28 @@ Our test suite is divided into **unit tests** and **integration tests**.
78133

79134
### Default Behavior
80135

81-
By default, integration tests are **excluded** from the test run. This is achieved by configuring `pytest` in our `pytest.ini` file (located in the `backend` directory):
136+
By default, integration tests are **excluded** from the test run. This is achieved by configuring `pytest` in our `pyproject.toml` file:
82137

83-
```ini
84-
[pytest]
85-
markers =
86-
integration: mark test as an integration test.
87-
addopts = -m "not integration"
138+
```toml
139+
[tool.pytest.ini_options]
140+
markers = [
141+
"integration: mark test as an integration test."
142+
]
143+
addopts = "-m 'not integration'"
88144
```
89145

90146
This configuration tells `pytest` to skip any test marked with `@pytest.mark.integration` when you run:
91147

92148
```bash
93-
pytest -v
149+
uv run pytest -v
94150
```
95151

96152
### Running Integration Tests
97153

98154
To run the integration tests, override the default marker filter by using the `-m` option:
99155

100156
```bash
101-
pytest -m integration
157+
uv run pytest -m integration
102158
```
103159

104160
> **Note:** Integration tests make real API calls and require the `OPENAI_API_KEY` environment variable to be set. Make sure you have this environment variable configured before running these tests.

backend/pyproject.toml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
[project]
2+
name = "gpteasers-backend"
3+
version = "0.1.0"
4+
description = "FastAPI backend for GPTeasers quiz generation app"
5+
authors = [
6+
{name = "DJSaundes1997@gmail.com"}
7+
]
8+
requires-python = ">=3.10"
9+
dependencies = [
10+
"openai",
11+
"fastapi",
12+
"uvicorn",
13+
"litellm",
14+
]
15+
16+
[project.optional-dependencies]
17+
dev = [
18+
"ruff",
19+
"pytest",
20+
"pytest-mock",
21+
]
22+
23+
[project.scripts]
24+
dev = "uvicorn fastapi_generate_quiz:app --reload --host 0.0.0.0 --port 8000"
25+
26+
[tool.ruff]
27+
line-length = 88
28+
target-version = "py310"
29+
30+
[tool.ruff.lint]
31+
select = ["E", "F", "W", "I"]
32+
33+
[tool.pytest.ini_options]
34+
markers = [
35+
"integration: mark test as an integration test."
36+
]
37+
addopts = "-m 'not integration'"
38+
testpaths = ["tests"]
39+
40+
[dependency-groups]
41+
dev = [
42+
"pytest>=8.4.2",
43+
"pytest-mock>=3.15.1",
44+
"ruff>=0.14.3",
45+
]

backend/pytest.ini

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)